Java线程在运行的生命周期中可能处于下表所示的6种不同的状态,在给定的一个时刻,线程只能处于其中的一个状态。
下面我们使用jstack工具,尝试查看示例代码运行时的线程信息,更加深入地理解线程状态,示例如代码如下所示。
package com.baowei.threadstate; public class ThreadState { public static void main(String[] args) { new Thread(new TimeWaiting(), "TimeWaiting Thread").start(); new Thread(new Waiting(), "Waiting Thread").start(); // 使用两个Blocked线程,一个获取锁成功,另一个被阻塞 new Thread(new Blocked(), "Blocked Thread-1").start(); new Thread(new Blocked(), "Blocked Thread-2").start(); } // 该线程不断的进行睡眠 static class TimeWaiting implements Runnable { public void run() { while (true) { // 不断的睡眠 try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } } } // 该线程在Waiting.class实例上等待 static class Waiting implements Runnable { public void run() { while (true) { synchronized (Waiting.class) { try { // 等待 Waiting.class.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } } // 该线程在Blocked.class实例上加锁后,不会释放锁 static class Blocked implements Runnable { public void run() { synchronized (Blocked.class) { // while (true) { try { Thread.sleep(100000); } catch (InterruptedException e) { e.printStackTrace(); } } } } } } 运行该示例,打开终端或者命令提示符,键入“jps”,输出如下。 [root@cent01 ~]# jps 11275 Jps 11262 ThreadState 可以看到运行示例对应的进程ID是11262,接着再键入“jstack 929”(这里的进程ID需要和读者自己键入jps得出的ID一致),部分输出如下所示。 "Blocked Thread-2" prio=10 tid=0xb7579800 nid=0x2c0a waiting for monitor entry [0xa0ec5000] java.lang.Thread.State: BLOCKED (on object monitor) at ThreadState$Blocked.run(ThreadState.java:48) - waiting to lock <0xa184a8c0> (a java.lang.Class for ThreadState$Blocked) at java.lang.Thread.run(Thread.java:745) "Blocked Thread-1" prio=10 tid=0xb7577c00 nid=0x2c09 waiting on condition [0xa0f16000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at ThreadState$Blocked.run(ThreadState.java:48) - locked <0xa184a8c0> (a java.lang.Class for ThreadState$Blocked) at java.lang.Thread.run(Thread.java:745) "Waiting Thread" prio=10 tid=0xb7576400 nid=0x2c08 in Object.wait() [0xa0f67000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0xa1849910> (a java.lang.Class for ThreadState$Waiting) at java.lang.Object.wait(Object.java:503) at ThreadState$Waiting.run(ThreadState.java:32) - locked <0xa1849910> (a java.lang.Class for ThreadState$Waiting) at java.lang.Thread.run(Thread.java:745) "TimeWaiting Thread" prio=10 tid=0xb7575400 nid=0x2c07 waiting on condition [0xa0fb8000] java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at ThreadState$TimeWaiting.run(ThreadState.java:17) at java.lang.Thread.run(Thread.java:745)通过示例,我们了解到Java程序运行中线程状态的具体含义。线程在自身的生命周期中,并不是固定地处于某个状态,而是随着代码的执行在不同的状态之间进行切换,Java线程状态变迁如下图:
由图4-1中可以看到,线程创建之后,调用start()方法开始运行。当线程执行wait()方法之后,线程进入等待状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态,而超时等待状态相当于在等待状态的基础上增加了超时限制,也就是超时时间到达时将会返回到运行状态。当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到阻塞状态。线程在执行Runnable的run()方法之后将会进入到终止状态。
Java将操作系统中的运行和就绪两个状态合并称为运行状态。阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态,但是阻塞在java.concurrent包中Lock接口的线程状态却是等待状态,因为java.concurrent包中Lock接口对于阻塞的实现均使用了LockSupport类中的相关方法。
Java并发编程的艺术