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
相关产品推荐
相关产品推荐

