• 线程的生命周期


    “ 新旧云组网”

    1、新建状态

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

    注意不能对已经启动的线程再次调用start()方法,否则会出现Java.lang.IllegalThreadStateException异常。

    2、就绪状态

           处于就绪状态的线程已经具备了运行条件,但还没有分配到CPU,处于线程就绪队列(尽管是采用队列形式,事实上,把它称为可运行池而不是可运行队列。因为cpu的调度不一定是按照先进先出的顺序来调度的),等待系统为其分配CPU。等待状态并不是执行状态,当系统选定一个等待执行的Thread对象后,它就会从等待执行状态进入执行状态,系统挑选的动作称之为“cpu调度”。一旦获得CPU,线程就进入运行状态并自动调用自己的run方法。

    提示:如果希望子线程调用start()方法后立即执行,可以使用Thread.sleep()方式使主线程睡眠一会儿,转去执行子线程。

    3、运行状态

          处于运行状态的线程最为复杂,它可以变为阻塞状态、就绪状态和死亡状态。

    处于就绪状态的线程,如果获得了cpu的调度,就会从就绪状态变为运行状态,执行run()方法中的任务。如果该线程失去了cpu资源,就会又从运行状态变为就绪状态。重新等待系统分配资源。也可以对在运行状态的线程调用yield()方法,它就会让出cpu资源,再次变为就绪状态。

    注: 当发生如下情况是,线程会从运行状态变为阻塞状态:

         ①、线程调用sleep方法主动放弃所占用的系统资源

         ②、线程调用一个阻塞式IO方法,在该方法返回之前,该线程被阻塞

         ③、线程试图获得一个同步监视器,但更改同步监视器正被其他线程所持有

         ④、线程在等待某个通知(notify)

         ⑤、程序调用了线程的suspend方法将线程挂起。不过该方法容易导致死锁,所以程序应该尽量避免使用该方法。

    当线程的run()方法执行完,或者被强制性地终止,例如出现异常,或者调用了stop()、desyory()方法等等,就会从运行状态转变为死亡状态。

    4、阻塞状态

          处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己的运行,进入阻塞状态。 

    在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续运行。有三种方法可以暂停Threads执行:

    1sleep方法  

      可以调用Thread的静态方法:public static void sleep(long millis) throws InterruptedException 使得当前线程休眠(暂时停止执行millis毫秒)。由于是静态方法,sleep可以由类名直接调用:Thread.sleep()。下面为代码示例:

    import java.util.Date;
    import java.text.SimpleDateFormat;
    class SleepTest implements Runnable {
        private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        public void run() {
            System.out.println("child thread begin");
            int i = 0;
            while (i++ < 5) {
                System.out.println(format.format(new Date()));
                try {
                    Thread.sleep(5000);
                }
    catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("child thread dead at: " + format.format(new Date()));
        }
        public static void main(String[] args) {
            Runnable r = new SleepTest();
            Thread thread = new Thread(r);
            thread.start();
            try {
                Thread.sleep(20000);
            }
     catch (InterruptedException e) {
                e.printStackTrace();
            }
            thread.interrupt();
            System.out.println("main method dead!");
        }
    }

    该程序的运行结果如下:

    child thread begin

    2009-02-06 04:50:29

    2009-02-06 04:50:34

    2009-02-06 04:50:39

    2009-02-06 04:50:44

    main method dead!

    java.lang.InterruptedException: sleep interrupted

    at java.lang.Thread.sleep(Native Method)

    at com.px1987.j2se.thread.p5.Thread4.run(Thread4.java:17)

    at java.lang.Thread.run(Unknown Source)

    2009-02-06 04:50:49

    child thread dead at: 2009-02-06 04:50:54

    2yield方法   线程让步,即线程运行到此,做出让步,让出CPU的使用权,从运行态直接进入就绪态

    class Thread5 implements Runnable {
        private String name;
    
        Thread5(String s) {
            this.name = s;
        }
    
        public void run() {
            for (int i = 1; i <= 50; i++) {
                System.out.println(name + ": " + i);
                if (i % 10 == 0) {
                    Thread.yield();
                }
            }
        }
    }
    
    
    public class YieldTest {
        public static void main(String[] args) {
            Runnable r1 = new Thread5("S1");
            Runnable r2 = new Thread5("S2");
            Thread t1 = new Thread(r1);
            Thread t2 = new Thread(r2);
            t1.start();
            t2.start();
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("main method over!");
        }
    }

    部分运行结果如下:可以看到,每到执行到yield方法,当前线程即停止,让另一进行继续执行。

    S2: 16
    S2: 17
    S2: 18
    S2: 19
    S2: 20
    S1: 7
    S1: 8
    S1: 9
    S1: 10
    main method over!
    S2: 21
    S2: 22
    S1: 11
    S1: 12
    S1: 13
    S1: 14
    S1: 15
    S1: 16
    S1: 17
    S1: 18
    S1: 19
    S1: 20
    S2: 23

    3join方法  线程插队   当某个(A)线程等待另一个线程(B)执行结束后,才继续执行时,使用join方法。Arun方法调用b.join()。下面为代码示例。

    
    当某个(A)线程等待另一个线程(B)执行结束后,才继续执行时,使用join方法。A的 run方法调用b.join()。下面为代码示例。
    package com.px1987.j2se.thread.join;
    class FatherThread implements Runnable {
        public void run() {
            System.out.println("爸爸想抽烟,发现烟抽完了");
            System.out.println("爸爸让儿子去买包红塔山");
            Thread son = new Thread(new SonThread());
            son.start();
            System.out.println("爸爸等儿子买烟回来");
            try {        //join含义:等待son线程执行完毕,father线程才继续执行
                son.join();
            } 
    catch (InterruptedException e) {
                System.out.println("爸爸出门去找儿子跑哪去了");
                System.exit(1);
            }
            System.out.println("爸爸高兴的接过烟开始抽,并把零钱给了儿子");
        }
    }
    package com.px1987.j2se.thread.join;
    class SonThread implements Runnable {
        public void run() {
            String tabs="						";
            System.out.println(tabs+"儿子出门去买烟");
            System.out.println(tabs+"儿子买烟需要10分钟");
            try {
                for (int i = 0; i < 10;) {
                    Thread.sleep(1000);
                    System.out.println(tabs+"儿子出去第" + ++i + "分钟");
                }
            } 
    catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(tabs+"儿子买烟回来了");
        }
    }
    package com.px1987.j2se.thread.join;
    public class JoinTest {
        public static void main(String[] args) {
            System.out.println("爸爸和儿子的故事");
              Thread father = new Thread(new FatherThread());
             father.start();

          // try {//当时间来到儿子出去买烟的时候,Father线程调用interrupt方法就会打断son线程的正常执行,从而father线程也就不必等待son线程执行完毕再行动了

          // Thread.sleep(5000);

          // } catch (InterruptedException e) {
          // e.printStackTrace();
          // }
          // father.interrupt();

    
    
        }
    }

    运行结果如下

    爸爸和儿子的故事
    爸爸想抽烟,发现烟抽完了
    爸爸让儿子去买包红塔山
    爸爸等儿子买烟回来
                                            儿子出门去买烟
                                            儿子买烟需要10分钟
                                            儿子出去第1分钟
                                            儿子出去第2分钟
                                            儿子出去第3分钟
                                            儿子出去第4分钟
                                            儿子出去第5分钟
                                            儿子出去第6分钟
                                            儿子出去第7分钟
                                            儿子出去第8分钟
                                            儿子出去第9分钟
                                            儿子出去第10分钟
                                            儿子买烟回来了
    爸爸高兴的接过烟开始抽,并把零钱给了儿子

    join()方法的一个重点是要区分出和sleep()方法的区别。join(2000)也是可以的,表示调用join()方法所在的线程最多等待2000ms,两者的区别在于:

    sleep(2000)不释放锁,join(2000)释放锁因为join()方法内部使用的是wait(),因此会释放锁。看一下join(2000)的源码就知道了,join()其实和join(2000)一样,无非是join(0)而已:

    当时间来到儿子出去买烟的时候,Father线程调用interrupt方法就会打断son线程的正常执行,从而father线程也就不必等待son线程执行完毕再行动了,运行结果如下:

    爸爸和儿子的故事
    爸爸想抽烟,发现烟抽完了
    爸爸让儿子去买包红塔山
    爸爸等儿子买烟回来
                            儿子出门去买烟
                            儿子买烟需要10分钟
                            儿子出去第1分钟
                            儿子出去第2分钟
                            儿子出去第3分钟
                            儿子出去第4分钟
    爸爸出门去找儿子跑哪去了

    5、死亡状态

          当线程的run()方法执行完,或者被强制性地终止,就认为它死去。这个线程对象也许是活的,但是,它已经不是一个单独执行的线程。线程一旦死亡,就不能复生。 如果在一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常。

  • 相关阅读:
    P4127 [AHOI2009]同类分布
    区间DP
    P3146 [USACO16OPEN]248
    P1241 括号序列
    P2858 [USACO06FEB]奶牛零食Treats for the Cows
    P2602 [ZJOI2010]数字计数&P1239 计数器&P4999 烦人的数学作业
    数位DP
    jquery生成元素注册事件无效,及事件委托的使用
    Jquery ajax运用执行顺序有误怎么解决
    html页面输入框input的美化
  • 原文地址:https://www.cnblogs.com/thiaoqueen/p/6562358.html
Copyright © 2020-2023  润新知