为何ReentrantLock在Demo中失效而synchronized可正常运行?
问题分析与解决方案
看起来你在对比ReentrantLock和synchronized的过程中遇到了典型的锁使用错误,我来帮你拆解问题所在:
核心问题根源
你的断言失败和局部锁无效,本质是两个常见的ReentrantLock使用误区:
1. 类级锁时:锁的保护范围不完整 + 未用finally保证解锁
synchronized方法会自动把整个方法体纳入锁的保护范围,包括你的断言语句;但ReentrantLock是手动锁,如果你没把**所有共享变量操作(包括断言)**都放在锁的保护区间内,或者解锁语句没放在finally块中,就会出现问题:
- 如果解锁语句在断言之前执行,那么解锁后其他线程可以立刻修改
count,导致断言时count的值不再是1 - 如果断言失败抛出
AssertionError,且解锁语句没在finally里,会导致锁永久被持有,后续线程无法获取锁(或出现竞态条件)
2. 局部锁时:锁的作用范围完全失效
当你把ReentrantLock改成方法内局部变量时,每个线程调用方法都会创建一个全新的锁实例——不同线程的锁彼此独立,根本无法实现互斥访问。多个线程可以同时修改静态变量count,自然会出现count++后的值大于1的情况,触发断言错误。
正确的实现方式
要解决这个问题,你需要遵守ReentrantLock的三个使用原则:
- 锁必须是多线程共享的实例(比如类级静态变量)
- 所有对共享变量的操作(包括断言)必须放在锁的保护范围内
- 用
finally块确保锁一定会被释放,避免锁泄漏
下面是修正后的代码:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockZero { private static int count = 0; // 类级共享锁,确保所有线程使用同一个锁实例 private static final ReentrantLock lock = new ReentrantLock(); public synchronized int getCount() { count++; assert count == 1 : "Synchronized count mismatch: " + count; count--; return count; } public int getCountUsingLock() { lock.lock(); // 先获取锁 try { // 所有对共享变量的操作都在锁保护下 count++; assert count == 1 : "ReentrantLock count mismatch: " + count; count--; return count; } finally { lock.unlock(); // 无论是否异常,都确保释放锁 } } public static void main(String[] args) { ExecutorService pool = Executors.newFixedThreadPool(2); ReentrantLockZero obj = new ReentrantLockZero(); for (int i = 0; i < 1000; i++) { pool.submit(obj::getCount); pool.submit(obj::getCountUsingLock); } pool.shutdown(); } }
验证效果
启用-ea参数运行这段代码,两个方法都不会触发AssertionError:
finally块保证了锁的释放,不会出现锁泄漏- 锁的保护范围覆盖了所有
count的操作和断言,确保了互斥访问 - 类级锁保证了多线程共享同一个锁实例,实现了正确的同步
内容的提问来源于stack exchange,提问作者Hearen
相关产品推荐
相关产品推荐

