Java 语言中关于线程的状态共分为6种,在 Thread 类里面定义了一个枚举类 State 来标识线程状态,分别为 NEW(新建)、RUNNABLE(运行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(计时等待)和TERMINATED(终止)。在 Java 代码中,如果可以通过访问 Thread 类的getStat()方法获取当前线程的状态。
NEW:新建状态
NEW 状态表示线程被创建但是未启动,也就是当一个 Thread 对象创建后并且没有调用 start() 方法之前,当前线程状态为 NEW。
public class NewStateExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> System.out.println("当前线程名称:" + Thread.currentThread().getName()));
System.out.println("当前线程状态:" + thread.getState());
}
}
RUNNABLE:运行状态
当调用 Thread 对象的 start() 方法后,线程状态由 NEW 转为 RUNNABLE。但是需要注意是,在 Java 中一个处于 RUNNABLE 状态的线程可能在运行,也可能没有运行而处于等待 CPU 分配资源。
public class RunnableStateExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
System.out.println("当前线程名称:" + Thread.currentThread().getName());
});
thread.start();
System.out.println("当前线程状态:" + thread.getState());
}
}
BLOCKED:阻塞状态
当一个线程进入 synchronized 代码块并且等待获取一个 monitor 锁时或者在调用Object.wait()方法后被唤醒并重新进入 synchronized 代码块后,线程处于 BLOCKED 状态。
示例:代码进入 synchronized 代码块并且等待过去一个 monitor 锁
public class BlockedState1Example {
public static void main(String[] args) {
Object obj = new Object();
Thread thread = new Thread(() -> {
synchronized (obj) {
System.out.println("获取到锁,线程运行");
}
});
synchronized (obj) {
thread.start();
System.out.println("线程状态:" + thread.getState());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
示例:线程调用 Object.wait() 方法后被唤起重新进入 synchroized 代码块
public class BlockedState2Example {
public static void main(String[] args) {
Object obj = new Object();
Thread thread1 = new Thread(() -> {
synchronized (obj) {
try {
System.out.println("子线程1运行成功,进入等待状态");
obj.wait();
System.out.println("子线程1的状态:" + Thread.currentThread().getState());
System.out.println("子线程1重新运行");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (obj) {
try {
// 模拟一些工作
System.out.println("子线程1的状态:" + thread1.getState());
System.out.println("子线程2执行一些工作");
Thread.sleep(2000);
System.out.println("子线程2工作结束,唤起其他线程");
obj.notifyAll();
System.out.println("子线程1的状态:" + thread1.getState());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
thread1.start();
thread2.start();
}
}
WAITING:等待状态
当一个线程执行了Object.wait()(不设置等待时间)、Thread.join()(不设置等待时间)或者LockSupport.park后,该线程的状态从 RUNNABLE 切换到 WAITING 状态,等待其他线程执行特定的操作。例如,一个线程 A 执行了某个对象的 wait() 方法,那么需要等待其他线程执行该对象的 notify() 或者 notifyAll() 方法后,线程 A 才能继续运行。又或者,一个线程 B 执行了 join() 方法,那么只能等待那个线程执行完,线程 B 才能继续执行。
示例:线程调用 join 方法等待其他线程执行完成
public class WaitingStateExample {
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
try {
Thread.sleep(3000);
System.out.println("线程1执行完毕");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
Thread thread2 = new Thread(() -> {
try {
thread1.join();
System.out.println("线程2执行完毕");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
});
thread2.start();
thread1.start();
System.out.println("线程2的状态:" + thread2.getState());
Thread.sleep(1000);
System.out.println("线程2的状态:" + thread2.getState());
}
}
TIMED_WAITING:计时等待状态
当一个线程执行了Object.wait()(设置超时时间)、Thread.join()(设置超时时间)、Thread.sleep()(设置超时时间)或者LockSupport.parkNanos/LockSupport.parkUntil后,该线程的状态从 RUNNABLE 切换到 TIMED_WAITING 状态。
TERMINATED:终止状态
当线程执行完成或者出现未处理的异常,线程的状态即为 TERMINATED 状态。
总结
状态切换
LockSupport.park/unpark 与 Object.wait/notify 的对比
| 特性 | LockSupport.park/uppark | Object.wait/notify |
|---|---|---|
| 是否需要锁 | 不需要 | 必须在 synchronized 代码块中 |
| 顺序问题 | 顺序无关,unpark 可以在 park 前面,效果会被记录下来,后续启动 park 不会阻塞线程 | 必须 先 wait 然后 notify |
| 适用场景 | 更灵活、低级别控制 | 较高层次的同步控制 |
| 虚假唤醒处理 | 可结合标记处理 | 必须结合条件变量处理 |
Thread.sleep 和 Object.wait 的对比
| 特性 | Object.wait() | Thread.sleep() |
|---|---|---|
| 释放锁 | 是 | 否 |
| 在哪调用 | synchronized 代码块 | 代码任意地方 |
| 唤醒方式 | notify() 或者 notifyAll() | 超时或中断 |
| 用途 | 线程间通信 | 线程暂停执行 |