目录
前言
PCB 中的状态主要分为就绪状态和阻塞状态两种,而在 Java 中,则对线程的状态做了进一步的细分,主要有:NEW、TERMINSTED、RUNNABLE、BLOCKED、WAITING 和 TIMED_WAITING 。下面就是对这几种状态进行逐一分析:
一、NEW 和 TERMINSTED
NEW 状态表示的是已经安排好了线程相对应的工作,但是还没开始做,就例如老师布置了作业,你也记下来在本子上了,但是还没开始做。具体点讲就是:Thread 对象已经创建好了,但是还没调用 start 方法,下面就通过代码来进行演示:
我们可以使用 Thread 类的 getState( ) 方法来获取到当前线程的状态
public class Demo1 {
public static void main(String[] args) {
Thread t = new Thread(() -> {
System.out.println("hello Thread!");
});
System.out.println(t.getState());
t.start();
}
}
从代码中我们可以看到,在 t 线程调用 start 方法之前,我们先打印出当前 t 线程所处的状态,因此我们可以看到执行 run 方法打印 hello Thread 之前先打印出了一个 NEW ,这便表明了未调用 start 方法但是已经创建出来了的 Thread 对象所处的状态就是 NEW 状态。
而 TERMINSTED 状态指的是线程已经完成了工作,再具体一点便是:线程已经执行完 run 方法了,但是 Thread 对象还未被销毁。
这是因为系统内核创建的线程和 Thread 对象的生命周期并不是完全一致的。
一般情况下都是先创建了 Thread 对象,然后再手动调用 start 方法,让系统内核创建出一个实际的线程。而消亡的时候,就可能是 Thread 先消亡,例如:Thread 对象在线程还未执行完 run 方法的时候就不再指向该线程了,并且不再指向任何对象,那么此时该引用就会被销毁回收。也有可能是线程先执行完,但是 Thread 对象还在。
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
System.out.println("hello Thread!");
});
t.start();
t.join();
System.out.println(t.getState());
}
}
上述代码中,我们使用了 join 方法让主线程等待 t 线程执行结束之后再打印出 t 线程的状态,就可以获取到 t 线程 run 方法执行完了之后的状态,由上图可知的确在 run 方法打印出 hello Thread 之后打印出 TERMINSTED 。
二、就绪状态
Java 中的就绪状态使用 RUNNABLE 来表示。
就绪状态分为以下两种:
1)线程正在 cpu 上运行
2)线程在排队,但是时刻准备着到 cpu 上执行
这两种状态都统称为就绪状态,因此无需纠结该线程创建出来之后是否在 cpu 执行调度。
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
while (true) {
}
});
t.start();
Thread.sleep(1000);
System.out.println(t.getState());
}
}
当我们执行上述代码时,start 方法启动 t 线程,然后先休眠 1000ms 保证 t 线程此时已经被启动,又由于 t 线程的 run 方法内是死循环,因此只要我们不手动停止,此时打印其状态都会为 RUNNABLE 。
三、阻塞状态
Java 中的阻塞状态分为三种,主要的区别就是造成阻塞的原因不同:
1)BLOCKED:因为锁发生了阻塞
2)WAITING:因为调用了 wait 发生了阻塞
3)TIMED_WAITING:因为调用了 sleep 或者带最大等待时间的 join 发生了阻塞,也即是带时间的阻塞则为 TIMED_WAITING,否则则为 BLOCKED 或者 WAITING
例如:
public class Demo1 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t.start();
Thread.sleep(1000);
System.out.println(t.getState());
}
}
上述代码中,仍然是先休眠 1000ms 保证 t 线程已经启动了,然后打印 t 线程的状态,由于 t 线程内为休眠 5000ms ,时间比较久,因此此时 t 线程为:因为 sleep 导致的阻塞状态——TIMED_WAITING 。
总结
上述的状态根据时间的先后,可以汇总成一张简单的图示:
充分了解这些线程状态,可以帮助我们解决线程执行过程中出现的 bug :在线程执行出现问题时,通过调试窗口或者 jconsole 等工具来观察线程,可以根据线程状态来判断出具体是哪里出现了问题,进而做出修改。