原书:《Java 并发编程的艺术第2版》 | 作者:方腾飞 魏鹏 程晓明 | 2023 年 9 月 | 机械工业出版社
Java 线程的状态
状态名称 | 说明 |
---|---|
NEW | 初始状态,线程被创建,但还没有调用 start() 方法 |
RUNNABLE | 运行状态,Java 线程将操作系统中的就绪和运行两种状态笼统的称作运行中 |
BLOCKED | 阻塞状态,表示线程阻塞于锁 |
WAITING | 等待状态,表示线程进入等待状态,进入该状态表示当前线程需要等待其他线程做出一些特定动作(通知或中断) |
TIMED_WAITING | 超时等待状态,该状态不同于 WAITING,它可以在指定的时间自行返回 |
TERMINATED | 终止状态,表示当前线程已经执行完毕 |
示例代码
ThreadState
|
|
SleepUtils
|
|
运行 ThreadState 后,可以通过 jps
命令查看 Java 进程号,然后通过 jstack 进程号
查看线程状态。
使用 jps 命令查看当前运行的 Java 进程
使用 jstack 命令查看线程堆栈信息,需要快速敲命令,不然 BlockedThread-1 就挂了
AI 分析结果
- TimeWaitingThread (线程 14): 处于 TIMED_WAITING (sleeping) 状态。 这意味着该线程正在调用 sleep 方法并等待一段时间。
- WaitingThread (线程 15): 处于 WAITING (on object monitor) 状态。 这意味着该线程正在等待某个对象的监视器 (monitor) 被释放。
- BlockedThread-1 (16): 同样处于TIMED_WAITING状态,也是因为调用了Thread.sleep()。
- BlockedThread-2 (线程 17): 处于 TIMED_WAITING (sleeping) 状态。 这意味着该线程正在调用 sleep 方法并等待一段时间。
注意
- Java 将操作系统中的就绪和运行两种状态笼统的称作运行状态
- 阻塞状态是线程阻塞进入 synchronized 关键字修饰的方法或代码块「获取锁」时的状态
- 但是阻塞在 java.concurrent 包中 Lock 接口的线程状态是 WAITING,而不是 BLOCKED,因为 java.concurrent 包中 Lock 接口对于阻塞的实现使用了 LockSupport 类中的相关方法
WAITING、BLOCKED 状态有什么区别?AI 回答
WAITING 状态
- 线程进入 WAITING 状态通常是因为调用了 Object.wait() 方法。
- 处于 WAITING 状态的线程会释放锁,并进入等待队列。
- 只有当其他线程调用 Object.notify() 或 Object.notifyAll() 方法唤醒等待队列中的线程时,WAITING 状态的线程才会被唤醒。
- WAITING 状态通常用于线程之间的同步和协作。
BLOCKED 状态
- 线程进入 BLOCKED 状态通常是因为尝试获取锁失败。
- 处于 BLOCKED 状态的线程会一直等待锁的释放,不会释放锁。
- 当锁被释放时,处于 BLOCKED 状态的线程会自动竞争锁,并有可能进入 RUNNING 状态。
- BLOCKED 状态通常用于防止多个线程同时进入临界区。
WAITING、BLOCKED 优缺点?AI 回答
WAITING
特点
- 等待通知:当线程调用 Object.wait()、Thread.join() 或 LockSupport.park() 方法时,会进入 WAITING 状态。此时,线程会放弃当前持有的所有锁,并进入无限期等待,直到其他线程通过调用 Object.notify()、Object.notifyAll() 或 LockSupport.unpark() 对其进行显式唤醒,或者线程被中断。
- 被动等待:处于 WAITING 状态的线程不参与任何锁的竞争,而是完全依赖于其他线程的操作来恢复执行。线程在等待期间不会消耗 CPU 资源,而是被操作系统挂起。
优点
- 资源节约:线程处于 WAITING 状态时,不会占用处理器时间,有利于减少系统开销,提高资源利用率。
- 协作机制:通过等待通知机制,线程间可以实现高效的协作和同步,例如生产者消费者模式、线程间的依赖等待等。
缺点
- 依赖外部唤醒:线程何时恢复执行完全取决于其他线程是否正确发送唤醒信号,若没有正确的通知机制或因编程错误导致唤醒信号丢失,可能会导致线程长期等待甚至死锁。
- 中断响应:虽然可以通过中断请求来唤醒 WAITING 线程,但在实际操作中可能需要额外的逻辑来处理中断请求,以确保线程能够正确响应中断并清理资源。
BLOCKED
特点
- 锁竞争:线程在试图获取一个由其他线程持有的监视器锁(如通过 synchronized 关键字修饰的代码块或方法)时,如果锁不可用,线程会进入 BLOCKED 状态。线程会等待锁的释放,一旦持有锁的线程释放锁,操作系统会选择一个合适的 BLOCKED 线程将其转换为就绪状态。
- 主动阻塞:线程处于 BLOCKED 状态是因为它在积极尝试获取锁资源,而并非主动放弃控制权进入等待。线程在等待锁的过程中可能会频繁切换,增加上下文切换的开销。
优点
- 互斥与同步:通过 BLOCKED 状态,Java 实现了线程间的互斥访问,确保同一时刻只有一个线程能访问临界区资源,避免数据竞争和一致性问题。
- 简化编程:使用 synchronized 等内置锁机制,使得并发编程相对简单,无需手动管理锁的获取与释放。
缺点
- 性能影响:频繁的锁竞争可能导致大量的上下文切换和CPU缓存失效,降低系统性能。特别是在锁粒度过粗或者锁争用激烈的情况下,可能成为性能瓶颈。
- 死锁风险:不当的锁顺序或嵌套锁使用可能导致死锁,即多个线程互相等待对方持有的锁,形成僵局,所有线程都无法继续执行。