线程的六个状态:创建、就绪、运行、等待、阻塞以及死亡
- 创建状态:在生成线程对象之后,调用该对象的
start() 方法之前,线程处于创建状态; - 就绪状态:当线程对象调用了
start() 方法之后,该线程就进入了就绪状态,但是CPU 还未调度这个线程执行任务,此时的线程就处于就绪状态。并且在线程开始运行之后,从等待或者睡眠中被激活之后,也会处于就绪状态; - 运行状态:处于就绪状态的线程被
CPU 调度,此时线程转为运行状态,开始运行run() 方法当中的代码。 - 等待状态/等待超时状态(主动进入):调用
wait() 方法,线程进入等待状态。调用notify()/notifyAll() 方法会唤醒线程,使线程从等待状态进入就绪状态或者运行状态。等待状态是没有时间戳的,如果没有被唤醒,会一直等待下去。另外,可以限定等待时间—wait(time) ,如果时间到了,即便是没有被唤醒,也会从等待状态恢复到就绪状态或运行状态。调用sleep(time) 会进入等待超时状态; - 阻塞状态(被动进入):通常是为了等待某个事件的发生(比如说某项资源就绪)之后再继续运行(由运行状态转为阻塞状态)。比如,当前线程调用了同步方法,即
synchronized 修饰的代码块或方法,如果没有拿到锁,就会进入阻塞状态,重新获取到锁,就会重新进入运行状态; - 死亡状态:如果一个线程的
run() 方法执行结束或者调用stop() 方法后,该线程就会死亡。对于已经死亡的线程,就无法再使用start() 方法令其进入就绪;
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
Java 线程状态变迁如图所示:
从图中可以看到,线程创建之后,调用start() 方法开始运行。当线程执行wait() 方法之 后,线程进入等待状态。进入等待状态的线程需要依靠其他线程的通知才能够返回到运行状态,而超时等待状态相当于在等待状态的基础上增加了超时限制,也就是超时时间到达时将会返回到运行状态。当线程调用同步方法时,在没有获取到锁的情况下,线程将会进入到阻塞状态。线程在执行Runnable.run() 的方法之后将会进入到终止状态。
注意:Java 将操作系统中的运行和就绪两个状态合并称为运行状态。阻塞状态是线程阻塞在进入synchronized 关键字修饰的方法或代码块(获取锁)时的状态,但是阻塞在java.concurrent 包中Lock 接口的线程状态却是等待状态,因为java.concurrent 包中Lock 接口对于阻塞的实现均使用了LockSupport 类中的相关方法。
通过以下代码运行时的线程信息,更加深入地理解线程状态:
public class ThreadState {
public static void main(String[] args) {
new Thread(new TimeWaiting(), "TimeWaitingThread").start();
new Thread(new Waiting(), "WaitingThread").start();
new Thread(new Blocked(), "BlockedThread-1").start();
new Thread(new Blocked(), "BlockedThread-2").start();
}
static class TimeWaiting implements Runnable {
@Override
public void run() {
while (true) {
SleepUtils.second(100);
}
}
}
static class Waiting implements Runnable {
@Override
public void run() {
while (true) {
synchronized (Waiting.class) {
try {
Waiting.class.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
static class Blocked implements Runnable {
@Override
public void run() {
synchronized (Blocked.class) {
while (true) {
SleepUtils.second(100);
}
}
}
}
}
class SleepUtils {
public static final void second(long seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
|