题目:高并发下 synchronized 竞争激烈导致线程上下文切换开销过大,如何定位并优化?
难度:high
标签:java/lock, java/concurrency, general/knowledge
评分:⭐⭐⭐☆☆(3/5)
可以通过检测线程状态通过jstack查看线程状态分布,如果有大量线程处于阻塞状态 ,那么可能是出现锁竞争激烈的情况,根据具体线程栈信息,确认阻塞位置,进行对应查看和优化; 竞争激烈,可能有两个原因,一个是并发度很高,大量线程访问,唤起竞争的线程很多,另一个是锁的粒度太大了,导致执行的时间较长,线程等待比较多; 根据不同情况做不同处理,大量线程访问的情况下,考虑是否可以跳过锁,使用异步或者缓存的方式不使用锁进行操作; 如果是线程粒度太大,内部执行内容时间过长那么就缩小粒度控制锁的范围,以及锁内部执行的内容进行不同的优化
优点:定位思路(jstack 看阻塞 + 线程栈定位热点)和归因(并发高 / 锁粒度大)都对,优化方向(去锁/缓存/缩小锁范围)也合理。
不足:缺量化定位——上下文切换要看 pidstat -w 的 cswch/nvcswch、vmstat 的 cs 列,锁竞争要看火焰图/JFR 的 monitor blocked、-XX:+PrintLocks;优化手段太笼统,缺锁分段、读写锁/StampedLock、LongAdder、CAS 乐观锁、减少临界区等具体手段。
补充:上下文切换本身不一定是问题,要看"切换是否带来收益";先用数据确认瓶颈是锁还是 CPU,再动手。
核心考点定位:能否用数据定位锁竞争/上下文切换,并给出分层优化手段。
知识点拆解:
jstack 看线程状态分布(大量 BLOCKED 指向 monitor 竞争)pidstat -w 看每秒上下文切换(cswch 自愿 / nvcswch 非自愿)vmstat 1 的 cs 列、JFR/火焰图的 "Java Monitor Blocked"、-XX:+PrintLocks考察方向:
延伸递进面试题:
【一句话结论】
面试官您好,我会先用数据确认瓶颈在锁竞争,再做分层优化。
【三点展开】
第一,定位:jstack 看大量 BLOCKED、pidstat -w 看上下文切换次数、火焰图看 monitor blocked,确认热点锁;
第二,归因:要么并发线程数远超 CPU 核数,要么临界区太长、锁粒度太粗;
第三,优化:缩小临界区、锁分段降粒度、读多写少换读写锁/StampedLock、高竞争计数用 LongAdder,必要时用 CAS/异步彻底去锁。
【一句边界】
当然,上下文切换不一定是坏事——要确认它真的没带来收益;也不能盲目"去锁",语义正确性优先于性能。