题目:什么是活锁,和死锁有什么区别?
难度:low
标签:java/concurrency-practice, java/concurrency, general/knowledge, difficulty/low
评分:⭐⭐⭐⭐☆(4/5)
活锁也是线程争抢资源产生的一个问题,危害性也非常高。活锁是线程持有资源,和其他线程出现争抢后就释放资源,然后重新再去争抢,多线程相互争抢然后被人抢就释放,导致多线程一直无法完成自己的任务一直在释放、争抢、释放循环,线程是 RUNNABLE 不是 BLOCKED 会空耗 CPU 资源;死锁则是线程相互阻塞,卡住无法继续下去大家谁也不释放自己持有的资源互相等待,线程 BLOCKED。
优点:
不足:
最后更新:2026-10-26 · 基于第 1 次作答
结论:活锁和死锁本质区别在线程状态——死锁 BLOCKED 卡住不动,活锁 RUNNABLE 空转但不推进。 关键词:BLOCKED vs RUNNABLE · 状态循环 · 随机退避 边界:三者都可能演化为饥饿,监控上靠线程状态分布 + CPU 使用区分
核心考点定位:能否准确区分活锁、死锁、饥饿三种并发故障,抓住各自的状态机特征和危害方式。
机制链(3 环):
Found one Java-level deadlock 检测证据锚点(去重 ≥6):
jstack:抓线程栈,看 java.lang.Thread.State: BLOCKED / RUNNABLE 分布Found one Java-level deadlock:JVM 内置死锁检测关键字(jstack / jconsole 输出)jstack <pid> 看 Found one Java-level deadlock;top -Hp 看 CPU 高的线程对比与权衡:
| 故障类型 | 线程状态 | CPU 消耗 | 是否推进 | 检测手段 | 解决方式 |
|---|---|---|---|---|---|
| 死锁 | BLOCKED | 低(等待) | 否 | jstack 检测 Found one Java-level deadlock | kill / dump 栈分析后修复 |
| 活锁 | RUNNABLE | 高(空转) | 否 | 线程 RUNNABLE 堆积 + CPU 高 + 业务 QPS 不涨 | 随机退避(jitter / back-off)破坏循环 |
| 饥饿 | RUNNABLE/BLOCKED | 不定 | 否 | 长时间无业务指标变化 | 公平锁 / 优先级随机化 |
常见误区:
适用边界:
ReentrantLock(true) 公平锁避免饥饿;无锁化编程从根上避开三者Found one Java-level deadlock);活锁没有内置检测,只能靠线程状态分布 + 业务指标侧写ThreadMXBean 自定义活锁监控【结论】 活锁和死锁本质区别在线程状态——死锁 BLOCKED 卡住不动,活锁 RUNNABLE 空转但不推进。
【三点】
第一,死锁:多个线程互相持有对方需要的资源,都进入 BLOCKED 状态等待对方释放,谁也不动,不消耗 CPU 也不推进。典型触发是四条件同时满足(互斥、占有且等待、不可剥夺、循环等待),线上靠 jstack 抓栈定位,JVM 内置 Found one Java-level deadlock 检测。
第二,活锁:线程都在主动变化状态试图推进,但状态变化恰好让彼此都无法前进,形成活循环——比如两个线程都在让步给对方,各自向左再向右反复退让。线程状态是 RUNNABLE 而不是 BLOCKED,所以空耗 CPU 资源,但业务实际不推进。这是活锁和死锁最大的差异:死锁"卡住不动",活锁"忙而不进"。
第三,监控识别与解法:死锁看 BLOCKED 堆积 + jstack 检测;活锁看 RUNNABLE 堆积 + CPU 高 + 业务指标无推进(QPS 不涨)。解法上死锁只能被外部打破(kill / dump 栈分析后修复);活锁靠随机退避(back-off with jitter)破坏循环对称性,让双方退让时间错开自然退出;饥饿靠公平锁或优先级随机化。
【边界】 三者都可能演化为饥饿——死锁若被中断可能变活锁;活锁若循环对称性未打破长期存在可能演化为饥饿(其他线程永远拿不到资源)。所以设计上要一开始就选无锁或公平锁避免这些问题。
| 日期 | 评分 | 备注 |
|---|---|---|
| 2026-10-26 | ⭐⭐⭐⭐☆ | 首次作答 |