图文详解jvm中的线程状态

来源:互联网 发布:mac 维修 编辑:程序博客网 时间:2024/06/17 22:14

       本文使用下面这张图详细介绍JAVA线程的六种状态    

 



            JAVA线程的六种状态详解


               在java.lang.Thread类中,定义了线程的以下六种状态(同一个时刻线程只能有一种状态)

               NEW(新建) 这个状态是指线程刚创建,但还未调用线程的start()方法进行启动,对应上图中的New状态

               RUNNABLE(可运行) 这个状态是指线程处于正常运行中,对应上图中的Runnable与Running状态,若获得CPU时间片则处于Running状态,否则处于Runnable状态

               BLOCKED(阻塞)这个状态是指当线程进入一个被synchronized修饰的方法或语句块(也叫临界区)时,如果锁已被其他线程所获取,则会进入此状态。对应上图中的锁定Blocked状态

               WAITING(无限等待)这个状态是指当线程获取到对象锁进入临界区内,调用了锁对象的wait()方法或者thread.join()方法后进入的状态。线程进入该状态会释放锁对象,并且等待被其他的线程所唤醒,处于这种状态的线程不会被分配CPU时间片。该状态对应上图中的等待Blocked状态

              TIMED_WAITING(有限等待)  这个状态是指当线程调用了以下方法后进入的状态。在指定时间后由系统将它们自动唤醒,处于这种状态的线程不会被分配CPU时间片。该状态对应上图中的Blocked状态

              1.Thread.sleep()方法

              2.Object.wait()方法(有timeout参数)

              3.thread.join()方法(有timeout参数)

              TERMINATED(死亡) 这个状态是指run()方法已执行完毕,线程进入死亡状态

    

            JAVA线程状态切换详解

        1.NEW状态

            当我们new一个线程,但还未调用线程的start()方法时,线程为NEW状态,使用thread.getState()方法可以获取线程状态,如下这段代码:

public class Test {public static void main(String[] args) {Thread t1 = new Thread(new Task1());System.out.println(t1.getState());}}class Task1 implements Runnable {@Overridepublic void run() {System.out.println();}}

           程序执行结果:

           


           2.RUNNABLE状态

              当线程调用start()方法后进入该状态,对应上图中New状态向Runnable状态的转变。但是注意,这不代表线程马上就开始运行程序,此时线程需要等待CPU给它分配时间片,分配到了CPU时间片才算是真正意义上的程序执行(对应上图中Runnable状态向Running状态的转变),CPU时间片执行完毕后线程需要等待CPU下一次给它分配CPU时间片(对应上图中Running状态向Runnable状态的转变)。

              当线程获得CPU时间片并正在执行程序时,如果此时线程调用yield()方法,线程会让出当前CPU时间片,并与其他线程一起竞争下一次的CPU时间片(有可能下一次的CPU时间片还是被该线程获得)         

public class Test {public static void main(String[] args) {Thread t1 = new Thread(new Task1());t1.start();System.out.println(t1.getState());}}class Task1 implements Runnable {@Overridepublic void run() {System.out.println();}}

              程序执行结果:

                 


              3.BLOCKED状态

                 当线程分配到CPU时间片并在执行程序时,假如此时需要进入一个synchronized方法或语句块,但是锁对象正在被其它线程所使用,而无法获取锁进入临界区,此时线程进入entry set区,状态为BLOCKED。对应上图中由Running状态向锁定Blocked状态的转变。如下这段代码:当线程t1获取test对象锁后执行blockTest()方法,此时t2线程进入test对象的entry set区,等待t1线程释放锁后竞争锁资源,此时t2线程的状态为BLOCKED    

public class Test {public static void main(String[] args) {Test test = new Test();Thread t1 = new Thread(new Task1(test));Thread t2 = new Thread(new Task2(test));t1.start();t2.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1:" + t1.getState());System.out.println("t2:" + t2.getState());}public void blockTest() {synchronized (this) {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}}class Task1 implements Runnable {private Test test;public Task1(Test test) {this.test = test;}@Overridepublic void run() {test.blockTest();}}class Task2 implements Runnable {private Test test;public Task2(Test test) {this.test = test;}@Overridepublic void run() {test.blockTest();}}    

              程序执行结果:

              


              4.WAITING状态

                  当线程在临界区内执行程序,此时如果执行的代码为对象锁的wait()方法或thread.join方法时,线程将释放锁,并且进入wait set区,等待被其它线程所唤醒,线程状态由RUNNABLE转变为WAITING(对应上图的Running状态转变为等待Blocked状态)。下面第一段代码说明线程执行临界区中锁对象的wait方法时,线程状态的变化,此时由于没有其它线程去唤醒该线程,所以该线程的状态会一直保持在waiting状态。下面第二段代码说明线程t2在执行t1.join()方法后由RUNNABLE状态转变为WAITING状态,等到t1线程的run方法执行完线程t2再执行,线程的join方法底层也是由wait()方法来实现的

                  当其它线程调用该对象的notify或notifyAll方法后,该线程被唤醒,并由wait set区进入entry set区,线程状态由WAITING转变为BLOCKED(对应上图中的等待Blocked转变为锁定Blocked)。如下面第三段代码,线程t1获取test对象的对象锁后进入临界区,当执行锁对象的wait()方法后释放锁,并进入WAITING状态,接着线程t2获取该对象锁并调用notify方法唤醒线程t1,唤醒后的线程t1由于没有其它线程与它竞争test对象的锁资源,所以跳过BLOCKED状态,直接获取对象锁执行之后代码,此时t1状态为Runnable。                      

public class Test {public static void main(String[] args) {Test test = new Test();Thread t1 = new Thread(new Task1(test));t1.start();try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("t1等待:" + t1.getState());}public void waitTest() {synchronized (this) {System.out.println("t1运行:" + Thread.currentThread().getState());try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}}}class Task1 implements Runnable {private Test test;public Task1(Test test) {this.test = test;}@Overridepublic void run() {test.waitTest();}}

                   程序执行结果:

                                   

public class Test {public static void main(String[] args) {Thread t1 = new Thread(new Task1());Thread t2 = new Thread(new Task2(t1));t1.start();t2.start();try {System.out.println("t2运行:" + t2.getState());Thread.sleep(1000);System.out.println("t2等待:" + t2.getState());} catch (InterruptedException e) {e.printStackTrace();}}}class Task1 implements Runnable {@Overridepublic void run() {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}class Task2 implements Runnable {private Thread thread;public Task2(Thread thread) {this.thread = thread;}@Overridepublic void run() {try {for (int i = 0; i < 10000; i++) {}thread.join();} catch (InterruptedException e) {e.printStackTrace();}}}

                    程序执行结果:

                             

public class Test {public static void main(String[] args) {Test test = new Test();Thread t1 = new Thread(new Task1(test));Thread t2 = new Thread(new Task2(test));t1.start();t2.start();try {Thread.sleep(1000);System.out.println("t1等待:" + t1.getState());} catch (InterruptedException e) {e.printStackTrace();}}public void waitTest() {System.out.println("t1运行:" + Thread.currentThread().getState());synchronized (this) {try {this.wait();System.out.println("t1唤醒后运行:"+ Thread.currentThread().getState());} catch (InterruptedException e) {e.printStackTrace();}}}public void notifyTest() {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (this) {this.notify();}}}class Task1 implements Runnable {private Test test;public Task1(Test test) {this.test = test;}@Overridepublic void run() {test.waitTest();}}class Task2 implements Runnable {private Test test;public Task2(Test test) {this.test = test;}@Overridepublic void run() {test.notifyTest();}}

              程序执行结果:

             


             5.TIMED_WAITING状态

          当线程分配到CPU时间片并在执行程序时,此时执行到的语句为线程的sleep()方法或对象的wait()方法(有timeout参数)或线程的join()方法(有timeout参数)时,线程由RUNNABLE状态转变为TIMED_WAITING状态(对应上图中的Running状态转变为Blocked状态)。下面第一段代码说明线程t1调用sleep()方法后进入TIMED_WAITING状态,休眠时间过去后重新转为RUNNABLE状态,另外sleep()方法是不释放锁的。第二段代码说明线程t1调用test对象的wait方法后进入TIMED_WAITING状态,等待时间过去后重新转为RUNNABLE状态,因为该wait()方法设置了等待时间,所以不需要通过其它线程来唤醒,等待时间过去后由系统自动唤醒该线程,另外wait()方法是释放锁的。第三段代码说明线程t2调用了线程t1的join方法后进入TIMED_WAITING状态,等待时间过去后重新转为RUNNABLE状态,join()方法底层也是通过wait()方法实现的         

public class Test {public static void main(String[] args) {Thread t1 = new Thread(new Task1());t1.start();try {System.out.println("t1运行:" + t1.getState());Thread.sleep(1000);System.out.println("t1等待:" + t1.getState());} catch (InterruptedException e) {e.printStackTrace();}}}class Task1 implements Runnable {@Overridepublic void run() {try {for (int i = 0; i < 10000; i++) {}Thread.sleep(3000);System.out.println("t1重新运行" + Thread.currentThread().getState());} catch (InterruptedException e) {e.printStackTrace();}}}

             程序执行结果:

                 

public class Test {public static void main(String[] args) {Test test = new Test();Thread t1 = new Thread(new Task1(test));t1.start();try {System.out.println("t1运行:" + t1.getState());Thread.sleep(1000);System.out.println("t1等待:" + t1.getState());} catch (InterruptedException e) {e.printStackTrace();}}public void waitTest() {synchronized (this) {try {this.wait(3000);} catch (InterruptedException e) {e.printStackTrace();}}}}class Task1 implements Runnable {private Test test;public Task1(Test test) {this.test = test;}@Overridepublic void run() {for (int i = 0; i < 10000; i++) {}test.waitTest();System.out.println("t1重新运行:" + Thread.currentThread().getState());}}

             程序执行结果:

                     

public class Test {public static void main(String[] args) {Thread t1 = new Thread(new Task1());Thread t2 = new Thread(new Task2(t1));t1.start();t2.start();try {System.out.println("t2运行:" + t2.getState());Thread.sleep(1000);System.out.println("t2等待:" + t2.getState());} catch (InterruptedException e) {e.printStackTrace();}}}class Task1 implements Runnable {@Overridepublic void run() {try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}}class Task2 implements Runnable {private Thread thread;public Task2(Thread thread) {this.thread = thread;}@Overridepublic void run() {try {for (int i = 0; i < 10000; i++) {}thread.join(3000);System.out.println("t2重新运行:" + Thread.currentThread().getState());} catch (InterruptedException e) {e.printStackTrace();}}}

              程序执行结果:

              


              5.TERMINATED状态     

            当线程运行完run()方法后,就转变为此状态。如下代码说明了线程由RUNNABLE状态转变为TERMINATED状态(对应上图Running状态向Dead状态的转变)

public class Test {public static void main(String[] args) {Thread t1 = new Thread(new Task1());t1.start();try {System.out.println("t1运行:" + t1.getState());Thread.sleep(3000);System.out.println("t1死亡:" + t1.getState());} catch (InterruptedException e) {e.printStackTrace();}}}class Task1 implements Runnable {@Overridepublic void run() {for (int i = 0; i < 10000; i++) {}}}

          程序执行结果:   

            

        

        总结: 线程的这六种状态其实就是一个线程完整的生命周期,当我们了解了不同阶段的线程的各种状态之后,对于我们分析线程间的死锁,线程的IO资源等待等等都有很大的帮助,反映在系统层面上,当我们程序的CPU使用率突然变高或者程序响应时间突然变慢等问题都可以通过那一时刻的线程分析进行问题的定位。

        以上均为作者本人的自我总结,如有不到之处请指正~


原创粉丝点击