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

lock.tryLock()是否线程安全?测试发现其未正确同步致结果异常

关于ReentrantLock.tryLock()导致线程安全问题的分析与修复

我仔细看了你的测试代码和问题描述,得先纠正一个误解:lock.tryLock()本身是线程安全的,你遇到的问题完全是因为对这个方法的使用逻辑不对。

问题根源

tryLock()的设计初衷是「非阻塞式尝试获取锁」:如果当前锁处于可用状态,它会获取锁并返回true;如果锁被其他线程持有,它不会像lock()那样阻塞等待,而是直接返回false。

你的代码里,一旦tryLock()返回false,就直接跳过了counter++或counter--的操作——这意味着大量的增量、减量动作根本没被执行。比如线程A尝试加一的时候,锁被线程B持有,那这次加一就直接放弃了;同理线程B的减一也可能被放弃。最终增减的次数不一致,结果自然是随机值,而不是预期的0。

而lock()和synchronized都是「阻塞式获取锁」:线程会一直等待,直到成功拿到锁再执行操作,所以所有的10000次加一和10000次减一都会被执行,最终结果正确。

修复方案

根据你的需求,有两种常见的修复方式:

方式1:循环重试直到获取锁(保留tryLock的非阻塞特性但确保操作执行)

如果你确实需要使用tryLock(),可以通过循环重试的方式,确保每次增减操作都能执行:

public void increment() { // 修正了方法名拼写错误
    boolean isLocked = false;
    try {
        // 循环尝试,直到成功获取锁
        while (!isLocked) {
            isLocked = lock.tryLock();
        }
        counter++;
    } finally {
        // 只有成功获取锁后才解锁
        if (isLocked) {
            lock.unlock();
        }
    }
}

public void decrement() {
    boolean isLocked = false;
    try {
        while (!isLocked) {
            isLocked = lock.tryLock();
        }
        counter--;
    } finally {
        if (isLocked) {
            lock.unlock();
        }
    }
}

方式2:直接使用lock()(更简洁可靠,推荐)

如果你的场景不需要非阻塞的特性,直接用lock()会更简单,逻辑也更清晰,这也是大多数线程安全场景的首选:

public void increment() {
    lock.lock();
    try {
        counter++;
    } finally {
        lock.unlock();
    }
}

public void decrement() {
    lock.lock();
    try {
        counter--;
    } finally {
        lock.unlock();
    }
}

额外小提示

你的代码里increemnt方法名拼写错误(少了个n),虽然不影响程序运行,但建议修正为increment,避免后续维护时产生混淆。

内容的提问来源于stack exchange,提问作者Sriharsha g.r.v

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:19:05