20250731-Park_打断大反转!一次_park_不阻塞,参数化日志竟成幕后黑手?

原文摘要

在 Java 并发学习中,lock-support 的 park() 与 interrupt() 常被认为是“中断后再次 park 不会阻塞”。

原文链接

进一步信息揣测

  • interrupt()会隐式调用unpark():Java中断机制内部会触发unpark()操作,将permit置为1,而不仅仅是设置中断标志。这一行为未在官方文档明确说明,需通过源码或深度测试才能发现。
  • permit与中断标志的独立性Thread.interrupted()仅清除Java层中断状态,但不会重置底层permit。这意味着即使中断标志被清除,残留的permit仍可能导致后续park()不阻塞,需额外消耗一次permit才能恢复阻塞能力。
  • 两次park()才能阻塞的隐藏逻辑:首次park()会消耗interrupt()隐式产生的permit,第二次park()才会真正阻塞。这一现象在常规文档中未被提及,属于实践中的“坑点”。
  • 日志打印方式影响线程调度:参数化日志(如log.debug("{}", msg))与字符串拼接日志(如log.debug("msg"))的细微差异可能改变线程执行时序,进而影响permit的消费顺序。这种隐蔽的副作用通常只有通过反复测试或内部经验才能察觉。
  • 时序敏感性park()/unpark()的行为高度依赖线程调度时序,不同环境(如日志框架、系统负载)可能导致表现不一致。开发中需针对边界条件进行严格测试,而非依赖文档的表面描述。