zoukankan      html  css  js  c++  java
  • 线程基础

    1、线程状态:

    • 新生状态

    new关键字和Thread类或其子类建立一个线程对象后,该线程对象就处于新生状态,处于新生状态的线程有自己的内存空间,通过调用start方法进入就绪状态(rumnable

     

    • 就绪状态

    处于就绪状态的线程已经具备了运行的条件,但还没有分配到cpu,处于线程就绪队列,等待系统为其分配CPU,等待状态并不是执行状态,当系统选定一个等待执行的Thread对象后,他/她就会从等待执行状态进入执行状态,系统挑选的动作称之为“CPU调度”。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。

    • 运行状态

    在运行状态的线程执行自己的run方法中代码,知道调度其他方法而终止、或等待某资源而阻塞或完成任务而死亡。如果在给定的时间片内没有执行结束,就会被系统给换下来回到等待执行状态

    • 阻塞状态

    处于运行状态的线程在某些情况下,如执行了sheep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态,在阻塞状态的线程不能进入就绪队列,只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续运行。

    • 死亡状态

    死亡状态是线程生命周期中的最后一个阶段,线程死亡的原因有两个。一个是正常运行的线程完成了它全部工作,另一个是线程被强制性的终止,如通过执行stopdestroy方法来终止一个线程(不推荐使用这两个方法,前者会产生异常,后者是强制终止,不会释放锁)

     

    2、停止线程

    1自然终止:线程体正常执行完毕

    2外部干涉

    1、在线程类中定义线程体使用的标识

    2、线程体使用该标识

    3、提供对外的方法改变该标识

    4、外部根据条件调用该方法即可

     

    3、阻塞

    1 join:合并线程

    2yield:暂停自己的线程   静态方法

    3 sleep:休眠,不释放锁

    *与时间相关:倒计时

    *模拟网络延时

     

    4、线程的同步(并发)

    1由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。

    2由于我们可以通过private关键字来保证数据对象只能被方法访问,所有我们只需针对方法提出一套机制,这套机制就是synchronized关键字,它包括两种用法:synchronized方法和synchronized块。

    同步多个线程访问同一份资源  确保资源安全--->线程安全

    • 同步块

    synchronized(引用类型|this|.class){

    }

    • 同步方法

    public synchronized void test1(){

    }

    线程安全:保证资源安全,相对效率低

    锁定范围过大:效率低下

    锁定范围过小:没有保证资源安全

     

    1

     1 public class SynDemo1 {
     2     public static void main(String[] args) {
     3         JvmThread thread1 = new JvmThread(100);
     4         JvmThread thread2 = new JvmThread(500);
     5         thread1.start();
     6         thread2.start();
     7     }
     8 }
     9  
    10 class JvmThread extends Thread{
    11     private long time;
    12     public JvmThread() {
    13     }
    14     public JvmThread(long time){
    15         this.time = time;
    16     }
    17     @Override
    18     public void run() {
    19         System.out.println(Thread.currentThread().getName()+
    20                 "-->创建:"+Jvm.getInstance1(time));
    21     }
    22 }
    23  
    24 /**
    25  * 单例设计模式
    26  * 确保一个类只有一个对象
    27  * 懒汉式(使用的创建对象):
    28  *         1、构造器私有化,避免外部直接创建对象
    29  *         2、声明一个私有的静态变量
    30  *         3、对外提供一个公共的静态方法访问该变量,
    31  *              如果变量没有对象,创建对象,否则直接返回
    32  * @author qjc
    33  *
    34  * 2016-3-13
    35  */
    36 class Jvm{
    37     private static Jvm instance = null;
    38     private Jvm() {
    39     }
    40     //线程不安全
    41     public static Jvm getInstance1(long time){
    42         if(null==instance){
    43             try {
    44                 Thread.sleep(time);//延时 放大错误
    45             } catch (InterruptedException e) {
    46                 e.printStackTrace();
    47             }
    48             instance = new Jvm();
    49         }
    50         return instance;
    51     }
    52     public static synchronized Jvm getInstance2(long time){
    53         if(null==instance){  //安全
    54             try {
    55                 Thread.sleep(time);//延时 放大错误
    56             } catch (InterruptedException e) {
    57                 e.printStackTrace();
    58             }
    59             instance = new Jvm();
    60         }
    61         return instance;
    62     }
    63     public static Jvm getInstance3(long time){
    64         //a b c d e都在此等待 -->效率不高 存在对象也需要等待
    65         synchronized (Jvm.class) {  //静态代码块里没有this
    66             if(null==instance){   //安全
    67                 try {
    68                     Thread.sleep(time);//延时 放大错误
    69                 } catch (InterruptedException e) {
    70                     e.printStackTrace();
    71                 }
    72                 instance = new Jvm();
    73             }
    74             return instance;
    75         }
    76     }
    77     //double checking 双重检查
    78     public static Jvm getInstance4(long time){
    79         //b c d e 直接返回对象-->效率 提供已经存在对象的访问效率
    80         if(null==instance){
    81             //a 创建对象
    82             synchronized (Jvm.class) {  //静态代码块里没有this
    83                 if(null==instance){  //安全
    84                     try {
    85                         Thread.sleep(time);//延时 放大错误
    86                     } catch (InterruptedException e) {
    87                         e.printStackTrace();
    88                     }
    89                     instance = new Jvm();
    90                 }
    91             }
    92         }
    93         return instance;
    94     }
    95 }

    5、死锁

    建立在同步之上,过多的同步容易造成死锁

     

    2

    /**
     * 过多同步容易造成死锁
     * @author qjc
     *
     * 2016-3-13
     */
    public class SynDemo2 {
        public static void main(String[] args) {
            Object goods = new Object();
            Object money = new Object();
            Test t1 = new Test(goods,money);
            Test t2 = new Test(goods,money);
            Thread proxy = new Thread(t1);
            Thread proxy2 = new Thread(t2);
            proxy.start();
            proxy2.start();
        }
    }
     
    class Test implements Runnable{
        Object goods;
        Object money;
        public Test(Object goods, Object money) {
            super();
            this.goods = goods;
            this.money = money;
        }
        @Override
        public void run() {
            while (true) {
                test();
            }
        }
        public void test() {
            synchronized (goods) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (money) {
                }
            }
            System.err.println("一手给钱");
        }
    }
    class Test2 implements Runnable{
        Object goods ;
        Object money ;
        public Test2(Object goods, Object money) {
            super();
            this.goods = goods;
            this.money = money;
        }
        @Override
        public void run() {
            while (true) {
                test();
            }
        }
        public void test() {
            synchronized (money) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (goods) {
                }
            }
            System.err.println("一手给货");
        }
    }

    解决死锁方法:生产者消费者模式(不是设计模式

    • 生产者消费者问题,也称有限缓冲问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程----即所谓的“生产者”和“消费者” ---在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。在此同时,消费者也在缓冲区消费这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
    • 要解决该问题,就必须谈生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常常用的方法由信号灯法、管程等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。

     

    3

    /**
     * 一个场景,共同的资源
     * 生产者消费者模式:信号灯法
     *     wait():等待,释放锁
     *      sleep():不释放锁
     *      notify()/notifyAll():唤醒
     * @author qjc
     *
     * 2016-3-13
     */
    public class Movie {
        private String pic;
        /**
         * 信号灯
         *     flag = T 生产者生产,消费者等待,生产完成后通知消费
         *     flag = F 消费者消费,生产者等待,消费完后通知生产
         */
        private boolean flag = true;
        public synchronized void play(String pic){
            if(!flag){ //生产者等待
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //开始生产
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("生产了"+pic);
            //生产完毕
            this.pic = pic;
            //通知消费
            this.notify();
            //生产者停下
            this.flag = false;
        }
        public synchronized void watch(){
            if(flag){ //消费者等待
                try {
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //开始消费
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(pic);
            //消费完毕
            System.out.println("消费了"+pic);
            //通知生产
            this.notifyAll();
            //消费停止
            this.flag = true;
        }
    }
     
     
    /**
     * 生产者
     * @author qjc
     *
     * 2016-3-13
     */
    public class Player implements Runnable{
        private Movie m;
        public Player(Movie m) {
            super();
            this.m = m;
        }
     
        @Override
        public void run() {
            for(int i=0;i<20;i++){
                if(0==i%2){
                    m.play("左青龙");
                }else{
                    m.play("右白虎");
                }
            }
        }
    }
     
    /**
     * 消费者
     * @author qjc
     *
     * 2016-3-13
     */
    public class Watcher implements Runnable {
        private Movie m;
        public Watcher(Movie m) {
            super();
            this.m = m;
        }
     
        @Override
        public void run() {
            for(int i=0;i<20;i++){
                m.watch();
            }
        }
    }
     
    /**
     * 测试
     * @author qjc
     *
     * 2016-3-13
     */
    public class App {
        public static void main(String[] args) {
            //共同资源
            Movie m = new Movie();
            //多线程
            Player p = new Player(m);
            Watcher w = new Watcher(m);
            new Thread(p).start(); 
            new Thread(w).start(); 
        }
    }

    sleep()wait()区别

     

    对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。

     

    sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。

     

    在调用sleep()方法的过程中,线程不会释放对象锁。

     

    而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象调用notify()方法后本线程才进入对象锁定池准备

     

    获取对象锁进入运行状态。

     

     

    6、任务调度

    • Timer 定时器类
    • TimerTask 任务类
    • 通过java timer timertask :spring的任务调度就是通过他们来实现的)
    • 在这种实现方式中,Timer类实现的是类似闹钟的功能,也就是定时或者每个一定时间触发一次线程。其实,Timer类本身实现的就是一个线程,只是这个线程是用来实现调用其他线程的。而TimerTask类似一个抽象类,该类实现了Runnable接口,所以按照前面的介绍,该类具备多线程的能力。
    • 在这种实现方式中,通过继承TimerTask是该类获得多线程的能力,将需要多线程执行的代码书写在run方法内部,然后通过Timer类启动线程的执行。
    • 在实际使用时,一个Timer可以启动任意多个TimerTask实现线程,但是多个线程之间会存在阻塞。所以如果多个线程之间如果需要完全独立运行的话,最好还是一个Timer启动一个TimerTask实现。

    4

    /**
     * @author qjc
     *
     * 2016-3-13
     */
    public class TimeDemo {
        public static void main(String[] args) {
            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println("so easy..");
                }
            }, new Date(System.currentTimeMillis()+1000)
            , 500);//参数3:每隔500秒调用一次,没有参数3只调用一次
        }
    }


    第三方框架:quartz   juc

     

     

    7、总结

     

    1、创建线程:

    1. 继承Thread
    2. 实现Runnable
    1. 实现Callable

    2、线程状态

    1)新生-->start -->就绪-->运行-->阻塞-->终止

    2终止线程

    3)阻塞:join yield sleep  

     


     

    3、线程的信息

       1Thread.currentThread

     2) 获取名称设置名称设置优先级判断状态

     

    4同步 ----对同一份资源



  • 相关阅读:
    HDU 1385 Minimum Transport Cost
    TOJ 3488 Game Dice
    TOJ 1717 WOJ
    POJ 2553 The Bottom of a Graph
    TOJ 1836 Play on Words
    利用OpenCV建立视差图像
    分享一个PyTorch医学图像分割开源库
    WACV 2021 论文大盘点-图像分割篇
    SolidWorks动画教程(1):简单动画制作
    VS2013安装及破解教程
  • 原文地址:https://www.cnblogs.com/dooor/p/5285483.html
Copyright © 2011-2022 走看看