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

为何log.debug会导致LockSupport.park()调用失效?

LockSupport.park()异常行为的原因分析

问题描述

线程t1两次调用LockSupport.park():首次调用后被主线程的t1.interrupt()唤醒,随后调用Thread.interrupted()清除中断状态,但第二次LockSupport.park()无法挂起线程;注释掉log.debug("test.......")语句后,第二次LockSupport.park()却能正常挂起。

代码示例

@Slf4j
public class Test08Park4 {
    public static void main(String[] args) throws InterruptedException{

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                LockSupport.park();
                /**
                 * With this log print, locksupport.park () cannot stop threads;
                 * If you comment this out, locksupport.park () can stop the thread
                 */
                log.debug("test.......");
                Thread.interrupted();
                LockSupport.park();
                log.debug("finished...");
            }
        });
        t1.start();
        sleep(1000);
        t1.interrupt();
    }
}

运行结果

未注释log.debug时

22:37:05.435 [Thread-0] DEBUG test.Test08Park4 - test.......
22:37:05.439 [Thread-0] DEBUG test.Test08Park4 - finished...

注释log.debug时

// 无输出(线程t1被挂起)

原因解析

核心本质

这个现象是Lombok的@Slf4j默认集成的Logback日志框架,在打印日志过程中会隐式保留或重置线程的中断标记,导致后续Thread.interrupted()无法彻底清除中断状态,最终LockSupport.park()因线程仍处于中断状态直接返回,无法挂起。

详细流程拆解

有log.debug的场景

  1. t1调用LockSupport.park()挂起(线程许可permit为0)。
  2. 主线程执行t1.interrupt(),t1的中断标记被设为true,LockSupport.park()因中断立即返回(此过程不消耗许可)。
  3. 执行log.debug:Logback在处理日志时,内部逻辑可能会检查线程状态,或在处理IO/线程上下文时捕获InterruptedException,随后通过Thread.currentThread().interrupt()重新设置中断标记,导致中断标记始终为true。
  4. 调用Thread.interrupted():虽然会临时清除中断标记,但日志框架的隐式操作已再次将其设为true。
  5. 再次调用LockSupport.park():由于线程中断标记仍为true,根据规则直接返回,后续finished...日志被打印。

注释log.debug的场景

  1. t1被interrupt()唤醒后,直接调用Thread.interrupted()彻底清除中断标记(此时标记为false,许可仍为0)。
  2. 调用LockSupport.park():线程无可用许可且未被中断,因此正常挂起,程序无输出。

验证方法

可在Thread.interrupted()前后添加中断状态打印,确认日志框架对标记的影响:

LockSupport.park();
log.debug("test.......");
boolean beforeClear = Thread.currentThread().isInterrupted();
boolean cleared = Thread.interrupted();
boolean afterClear = Thread.currentThread().isInterrupted();
log.debug("before clear: {}, cleared: {}, after clear: {}", beforeClear, cleared, afterClear);
LockSupport.park();

若有log.debug时afterClear为true,即可证明日志框架重置了中断标记。

内容的提问来源于stack exchange,提问作者zheng peng

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 13:55:16