一句话说透Java里面的ReentrantLock

192 阅读2分钟

ReentrantLock(可重入锁)  是 Java 中比 synchronized 更灵活的锁工具,你可以把它想象成  “智能门禁卡” ,允许同一个线程多次进入(可重入),还能设置排队规则(公平锁),甚至设置超时或中断等待。下面用最直白的话拆解它的核心特性:


一、核心特点

  1. 可重入

    • 同一线程 可以重复获取同一把锁,避免自己卡死自己。
    • 示例:递归方法中多次加锁。
    lock.lock();  
    try {  
        // 方法A内再次获取锁  
        lock.lock();  
        try { /* ... */ } finally { lock.unlock(); }  
    } finally { lock.unlock(); }  
    
  2. 公平性选择

    • 公平锁:先到先得,严格按请求顺序分配锁(性能较低)。

    • 非公平锁:允许插队,提高吞吐量(默认模式)。

    ReentrantLock fairLock = new ReentrantLock(true); // 公平锁  
    
  3. 灵活控制

    • 尝试获取锁tryLock() 立即返回是否成功。
    • 超时等待tryLock(5, TimeUnit.SECONDS)
    • 中断等待lockInterruptibly() 允许外部打断线程等待。

二、与 synchronized 的对比

对比项ReentrantLocksynchronized
锁获取方式手动 lock() 和 unlock()自动获取和释放(代码块结束)
可中断✅ 支持❌ 不支持
公平性✅ 可设置公平锁❌ 非公平锁
条件变量✅ 支持多个 Condition❌ 只有一个等待队列

三、使用场景

  1. 需要精细控制锁的获取和释放

    ReentrantLock lock = new ReentrantLock();  
    lock.lock();  
    try {  
        // 临界区代码  
    } finally {  
        lock.unlock(); // 必须手动释放,防止死锁  
    }  
    
  2. 处理复杂线程协作(如生产者-消费者)

    Condition notFull = lock.newCondition();  // 队列未满条件  
    Condition notEmpty = lock.newCondition(); // 队列非空条件  
    
    // 生产者:队列满时等待  
    public void produce() {  
        lock.lock();  
        try {  
            while (queue.isFull()) {  
                notFull.await(); // 释放锁并等待  
            }  
            queue.add(item);  
            notEmpty.signal(); // 唤醒消费者  
        } finally {  
            lock.unlock();  
        }  
    }  
    
  3. 避免死锁(可中断、超时)

    if (lock.tryLock(3, TimeUnit.SECONDS)) {  
        try { /* ... */ } finally { lock.unlock(); }  
    } else {  
        // 超时未获取锁,执行其他逻辑  
    }  
    

四、注意事项

  1. 必须手动释放锁

    • 忘记 unlock() 会导致锁泄漏,其他线程永久等待。
    • 务必在 finally 块中释放锁。
  2. 避免嵌套过深

    • 重入次数过多可能导致逻辑复杂,难以维护。
  3. 公平锁慎用

    • 公平锁性能较低,仅在严格要求顺序时使用。

五、性能优化技巧

  • 减少锁粒度:锁的范围尽量小。
  • 用 tryLock() 替代阻塞获取:避免线程长时间等待。
  • 合理使用读写锁(ReentrantReadWriteLock :读多写少时更高效。

六、总结

ReentrantLock 是 synchronized 的增强版

  • 优势:可中断、超时、公平锁、条件变量。
  • 代价:需手动管理锁,代码稍复杂。

适用场景

  • 需要更细粒度的锁控制。
  • 高并发且需要公平性的场景。
  • 复杂线程协作(如多条件等待)。

口诀
「ReentrantLock 真灵活,可重入来可中断
公平非公平随意选,条件变量更便捷
手动加锁要牢记,finally里解锁别忘记!」