ReentrantLock 的典型使用场景和实现方法

基本概念

ReentrantLock 是 Java 幑发包中提供的可重入互斥锁,相比 synchronized 关键字提供了更高的灵活性和功能。

典型使用场景

1. 防止重复提交

防止用户重复点击按钮导致的重复业务处理。

2. 缓存双检锁机制

在缓存失效时,防止多个线程同时重建缓存。

3. 资源竞争控制

对共享资源的访问进行精确控制。

4. 定时任务并发控制

确保同一时刻只有一个定时任务实例运行。

实现方法

方法一:在 Service 层直接使用

@Service
public class BusinessService {
    
    private final ReentrantLock lock = new ReentrantLock();
    
    public void processBusinessLogic(String key) {
        lock.lock();
        try {
            // 执行核心业务逻辑
            doSomething(key);
        } finally {
            lock.unlock();
        }
    }
    
    private void doSomething(String key) {
        // 具体业务实现
    }
}

方法二:使用静态 Map 管理多个锁

@Service
public class MultiKeyService {
    
    private static final Map<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
    
    public void processByKey(String key) {
        ReentrantLock lock = lockMap.computeIfAbsent(key, k -> new ReentrantLock());
        
        lock.lock();
        try {
            // 处理特定 key 的业务逻辑
            handleBusiness(key);
        } finally {
            lock.unlock();
        }
    }
    
    private void handleBusiness(String key) {
        // 具体业务实现
    }
}

方法三:封装为工具类使用

@Component
public class LockUtil {
    
    private static final Map<String, ReentrantLock> lockMap = new ConcurrentHashMap<>();
    
    public <T> T executeWithLock(String key, Supplier<T> supplier) {
        ReentrantLock lock = lockMap.computeIfAbsent(key, k -> new ReentrantLock());
        lock.lock();
        try {
            return supplier.get();
        } finally {
            lock.unlock();
        }
    }
    
    public void executeWithLock(String key, Runnable runnable) {
        ReentrantLock lock = lockMap.computeIfAbsent(key, k -> new ReentrantLock());
        lock.lock();
        try {
            runnable.run();
        } finally {
            lock.unlock();
        }
    }
}

// 使用示例
@Service
public class BusinessService {
    
    @Autowired
    private LockUtil lockUtil;
    
    public void processData(String key) {
        lockUtil.executeWithLock(key, () -> {
            // 执行业务逻辑
            doProcess(key);
        });
    }
}

方法四:使用 tryLock 避免阻塞

@Service
public class TimeoutControlService {
    
    private final ReentrantLock lock = new ReentrantLock();
    
    public boolean processWithTimeout() {
        try {
            if (lock.tryLock(3, TimeUnit.SECONDS)) {
                try {
                    // 执行业务逻辑
                    doProcess();
                    return true;
                } finally {
                    lock.unlock();
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return false;
    }
    
    private void doProcess() {
        // 具体业务实现
    }
}

在 Spring Bean 中的注意事项

1. 锁的作用域

@Service
public class SingletonService {
    
    // 实例变量 - 同一个锁对象
    private final ReentrantLock lock = new ReentrantLock();
    
    // 每次调用创建新锁 - 锁失效
    // private ReentrantLock getLock() { return new ReentrantLock(); }
}

2. 异常处理

@Service
public class ExceptionSafeService {
    
    private final ReentrantLock lock = new ReentrantLock();
    
    public void safeProcess() {
        lock.lock();
        try {
            // 业务逻辑可能会抛出异常
            riskyOperation();
        } finally {
            // 必须在 finally 中释放锁
            lock.unlock();
        }
    }
}

与 @Transactional 结合使用的注意事项

@Service
public class TransactionalLockService {
    
    private final ReentrantLock lock = new ReentrantLock();
    
    // 推荐:先加锁后开启事务
    public void correctWay() {
        lock.lock();
        try {
            transactionalMethod();
        } finally {
            lock.unlock();
        }
    }
    
    @Transactional
    public void transactionalMethod() {
        // 数据库操作
    }
}

最佳实践总结

  1. 锁的粒度:根据业务需求合理设计锁的粒度
  2. 异常安全:始终在 finally 块中释放锁
  3. 避免死锁:统一加锁顺序,避免嵌套锁
  4. 性能考虑:对于竞争不激烈的场景,synchronized 可能更合适
  5. 监控告警:添加锁等待时间监控,及时发现性能瓶颈

ReentrantLock 在 Spring Boot 中主要用于需要更细粒度控制并发访问的场景,相比 synchronized 提供了更多的功能和灵活性。

posted @ 2025-11-28 13:47  yub4by  阅读(0)  评论(0)    收藏  举报