You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为什么在parkAndCheckInterrupt加断点后AQS自定义自旋打印多了一次?

问题原因分析

这个差异是调试器的隐式unpark操作导致的,核心逻辑和执行流差异如下:

先理清楚AQS acquireQueued 的基础执行逻辑

你添加的打印在for(;;)循环的第一行,每进入一次循环就会打印一次。正常情况下,acquireQueued中线程抢锁失败会进入parkAndCheckInterrupt阻塞,只有两种情况会从park中唤醒:

  1. 持有锁的线程调用unlock触发unpark
  2. 线程被其他线程调用interrupt()中断
    唤醒后会重新进入for(;;)循环尝试抢锁,抢锁失败就会再次阻塞。

正常运行时Thread-2的执行流

  1. 刚加入队列时前两次循环:两次尝试抢锁失败,调整前驱节点状态为SIGNAL后进入park阻塞,对应前两次打印
  2. 主线程调用thread2.interrupt(),线程被唤醒,执行Thread.interrupted()返回true并清除中断标记,重新进入循环打印第三次,此时thread0还持有锁,抢锁失败再次进入park阻塞,没有后续唤醒操作,所以不会再打印
    和你给出的正常结果完全匹配。

加断点后的额外执行逻辑

你在parkAndCheckInterrupt的return Thread.interrupted();行加了断点,这行的执行时机是park唤醒之后、清除中断标记之前:

  1. thread2被中断唤醒后命中断点,被调试器挂起
  2. 调试器为了恢复被断点挂起的线程,会隐式调用一次LockSupport.unpark(thread2),给线程新增了一个可用的park许可
  3. 放行断点后,线程走完中断唤醒的原有逻辑,第三次打印后再次调用park(),这时候直接消费了调试器额外给的unpark许可,不需要任何其他唤醒操作就直接返回
  4. 线程又一次进入for(;;)循环,多打印了一次,之后再次抢锁失败进入正常阻塞
    这就是多出来一次打印的原因。

验证方法

你可以把断点移到LockSupport.park(this)行之前,或者把断点的挂起策略改成「不挂起线程只打印日志」,就不会出现多打印的情况。


内容的提问来源于stack exchange,提问作者A Xuan of programmer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 10:15:07