3. 线程状态及其转化
线程是轻量级进程,所以线程和进程状态一致。
Java 线程状态转化图:
3.1 Java 线程的 6 个状态
Thread.State
源码:
public enum State {
NEW, // 新创建的线程,未调用 start() 方法
RUNNABLE, // 线程正在运行中:可能是在 JVM 中运行,也可能在等待 CPU 时间片
BLOCKED, // 阻塞状态: 正等待锁的释放以进入同步区
WAITING, // 等待状态: 需要被其他线程唤醒才能重新进入 RUNNABLE 状态
TIMED_WAITING, // 超时等待状态: 等待一个具体的时间段,到期会被自动唤醒
TERMINATED; // 线程执行结束
}
start()
方法只能调用一次,即使该线程已经执行完毕threadStates
变量在start()
方法未运行时为0
,第一次调用start()
方法后,值会改变;而当线程执行完毕后,该变量会变成2
,代表线程TERMINATED
- 以下情况会使线程进入
WAITING
状态:Object.wait()
:使当前线程处于等待状态直到另一个线程唤醒它;Object.wait()
会释放锁
Thread.join()
:让调用者等待当前线程执行完毕,底层调用的是Object.wait()
;LockSupport.park()
:除非获得调用许可,否则禁用当前线程进行线程调度。
- 以下情况会使线程进入
TIMED_WAITING
状态:Thread.sleep(long millis)
:使当前线程睡眠指定时间;sleep()
不会释放锁
Object.wait(long timeout)
:线程休眠指定时间,等待期间可以通过notify()
或notifyAll()
唤醒;notify()
会随机唤醒单个等待锁的线程notify()
会唤醒所有等待锁的线程
Thread.join(long millis)
:等待当前线程最多 millis 毫秒,如果 millis=0,则不等待;LockSupport.parkNanos(long nanos)
: 除非获得调用许可,否则在指定时间内禁止当前线程进行线程调度;LockSupport.parkUntil(long deadline)
:与上面类似。
3.2 线程中断 interrupt()
Java 线程中断机制是一种协作机制。
- 中断操作不能直接终止该线程的运行,而是把对应线程的中断状态设置为 true,然后被中断的线程可以选择如何去处理中断请求,或者不处理中断,继续执行下去
3.2.1 Java 中线程中断的方法
Thread.interrupt()
:中断线程。并不会立即停止线程,而是设置线程的中断状态为true
(默认是false
);Thread.interrupted()
:测试当前线程是否被中断,返回线程当前的中断标志位。调用该方法会影响线程的中断状态:- 调用
interrupted()
方法会反转线程的中断状态。
- 调用
Thread.isInterrupted()
:测试当前线程是否被中断。- 调用这个方法不会影响线程的中断状态。
3.3 join()
如果一个线程实例 A 执行了 threadB.join()
, 其含义是:当前线程 A 会等待 threadB 线程终止后 threadA 才会继续执行。
3.4 sleep()
sleep()
会使线程休眠,只是让出 CPU 使用权,但不会放弃锁。
3.5 wait()
wait()
方法必须在同步方法或者同步块中执行,即线程必须已经获得了锁。
wait()
方法调用会释放锁,线程会进入等待池,遇到 notify()
或 notifyAll()
后,才会离开等待池,变成可运行状态。
3.6 yield()
方法调用后,该线程会让出 CPU 使用权,重新参与 CPU 时间片的竞争。
- 线程从 Running 状态转变为 Runnable 状态。
- 下一次 CPU 时间片会根据线程优先级来确定,也可能该线程在让出 CPU 后,还会立即获得 CPU 时间片
- 只能使同优先级的线程有执行的机会