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 时间片
- 只能使同优先级的线程有执行的机会