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

双线程自定义Lock实现死锁问题原因排查求助

锁死锁问题分析

你实现的是双线程场景下的Peterson锁变种,算法逻辑层面本身不存在死锁问题,你遇到的类死锁现象本质是Java内存模型导致的可见性问题,同时代码还存在互斥性被破坏的风险,具体原因如下:

  • 共享变量未加volatile修饰,存在可见性问题
    Java内存模型中,所有变量默认存储在主内存,每个线程拥有独立的工作内存,线程对变量的读写优先操作工作内存中的副本,默认不会主动将本地修改刷新到主内存,也不会主动拉取主内存的最新值。
    你的代码中turn变量和flag数组都没有添加volatile修饰,当一个线程修改了turn或者flag的值,另一个线程可能长期感知不到最新修改,导致一直卡在循环等待逻辑中,表现出来的现象和死锁完全一致。
    典型触发场景:
    1. 线程1获取锁执行完临界区代码后,在unlock方法中修改turn = 0、flag[1] = false,但修改仅保存在线程1的工作内存中,没有及时刷新到主内存
    2. 线程0此时还卡在内部空循环while (turn == other){}中,一直读取自己工作内存里旧的turn = 1的值,永远无法退出循环,最终两个线程都无法继续执行
      这也符合你提到的「死锁场景很难构造」的特点:可见性问题的触发依赖JVM的实际运行策略,属于偶发问题,不是必然复现。
  • 存在指令重排序风险,会破坏互斥性
    没有volatile修饰的情况下,JVM会对无依赖关系的指令做重排序优化,比如flag[tid] = true的操作可能被重排序到while (flag[other] == true)判断之后,导致两个线程同时判断对方的flag为false,同时进入临界区,锁的互斥性完全失效。
修复方案

只需要给两个共享变量添加volatile修饰,即可解决可见性和指令重排序问题:

private volatile int turn = 0;
private volatile boolean [] flag = new boolean [2];

注意Java中数组加volatile修饰的是数组的引用,如果需要保证数组内部元素的修改也满足可见性要求,你可以把flag拆成两个独立的volatile boolean变量:

private volatile boolean flag0 = false;
private volatile boolean flag1 = false;

内容的提问来源于stack exchange,提问作者August Jelemson

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 20:06:02