一、ReentrantLock 核心架构

1. 类继承关系

ReentrantLock
    ├── Lock 接口
    ├── Serializable 接口
    └── 内部类:
        ├── Sync (extends AbstractQueuedSynchronizer)
        │   ├── NonfairSync
        │   └── FairSync
        └── ConditionObject

2. 核心组件

public class ReentrantLock implements Lock, java.io.Serializable {
    private final Sync sync;  // 核心同步器
    
    abstract static class Sync extends AbstractQueuedSynchronizer {
        // AQS 的实现
    }
    
    static final class NonfairSync extends Sync {}
    static final class FairSync extends Sync {}
}

二、AQS(AbstractQueuedSynchronizer)原理

1. AQS 核心数据结构

public abstract class AbstractQueuedSynchronizer {
    // 同步状态
    private volatile int state;
    
    // 等待队列(CLH变种)
    private transient volatile Node head;
    private transient volatile Node tail;
    
    static final class Node {
        volatile int waitStatus;     // 等待状态
        volatile Node prev;          // 前驱节点
        volatile Node next;          // 后继节点
        volatile Thread thread;      // 等待线程
        Node nextWaiter;            // Condition队列链接
    }
}

2. CLH队列工作流程

┌─────────┐    ┌─────────┐    ┌─────────┐    ┌─────────┐
│ ThreadA │ -> │ ThreadB │ -> │ ThreadC │ -> │ ThreadD │
│ (持有锁) │    │ (等待)  │    │ (等待)  │    │ (等待)  │
└─────────┘    └─────────┘    └─────────┘    └─────────┘

三、公平锁 vs 非公平锁

1. 实现差异对比

// 非公平锁获取锁的流程
final void lock() {
    if (compareAndSetState(0, 1))  // 尝试直接抢锁
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);
}

// 公平锁获取锁的流程
final void lock() {
    acquire(1);  // 直接进入队列排队
}

// 公平锁的tryAcquire方法
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    if (c == 0) {
        // 关键区别:检查队列中是否有前驱节点
        if (!hasQueuedPredecessors() && 
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 重入逻辑...
}

2. 性能对比

场景 公平锁 非公平锁
高竞争场景 吞吐量低 吞吐量高
线程切换 频繁 较少
饥饿问题 可能存在
实际应用 较少 默认策略

四、可重入性实现原理

1. 重入计数机制

protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
    
    if (c == 0) {
        // 第一次获取锁
        if (!hasQueuedPredecessors() && 
            compareAndSetState(0, acquires)) {
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 重入:检查当前线程是否持有锁
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;  // 增加重入次数
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    return false;
}

// 释放锁时的重入计数
protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    
    boolean free = false;
    if (c == 0) {  // 完全释放锁
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

五、Condition 条件变量

1. Condition 原理

public class ConditionObject implements Condition {
    private transient Node firstWaiter;   // 条件队列头
    private transient Node lastWaiter;    // 条件队列尾
    
    // 等待方法
    public final void await() throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        Node node = addConditionWaiter();  // 添加到条件队列
        int savedState = fullyRelease(node);  // 完全释放锁
        int interruptMode = 0;
        
        while (!isOnSyncQueue(node)) {  // 不在同步队列中
            LockSupport.park(this);      // 阻塞
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                break;
        }
        
        // 被唤醒后重新获取锁
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        if (node.nextWaiter != null)
            unlinkCancelledWaiters();
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
    }
}

2. 等待队列 vs 条件队列

同步队列(CLH队列):
┌───────┐   ┌───────┐   ┌───────┐
│ NodeA │←→│ NodeB │←→│ NodeC │
└───────┘   └───────┘   └───────┘
  竞争锁        等待锁      等待锁

条件队列(单向链表):
┌───────┐   ┌───────┐   ┌───────┐
│ NodeX │→  │ NodeY │→  │ NodeZ │→ null
└───────┘   └───────┘   └───────┘
等待条件1    等待条件1    等待条件2

六、业务场景使用详解

场景1:线程安全的缓存系统

public class Cache<K, V> {
    private final Map<K, V> cache = new HashMap<>();
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();
    private final int maxSize;
    
    public Cache(int maxSize) {
        this.maxSize = maxSize;
    }
    
    public V get(K key) {
        lock.lock();
        try {
            // 等待直到缓存不为空
            while (cache.isEmpty()) {
                notEmpty.await();
            }
            return cache.get(key);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return null;
        } finally {
            lock.unlock();
        }
    }
    
    public void put(K key, V value) {
        lock.lock();
        try {
            // 等待直到缓存不满
            while (cache.size() >= maxSize) {
                notFull.await();
            }
            cache.put(key, value);
            notEmpty.signal();  // 通知等待的消费者
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
    
    public boolean remove(K key) {
        lock.lock();
        try {
            boolean removed = cache.remove(key) != null;
            if (removed) {
                notFull.signal();  // 通知生产者可以继续添加
            }
            return removed;
        } finally {
            lock.unlock();
        }
    }
}

场景2:数据库连接池

public class ConnectionPool {
    private final LinkedList<Connection> pool = new LinkedList<>();
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition notEmpty = lock.newCondition();
    private final Condition notFull = lock.newCondition();
    private final int maxSize;
    private int activeCount = 0;
    
    public ConnectionPool(int maxSize) {
        this.maxSize = maxSize;
    }
    
    public Connection getConnection(long timeout, TimeUnit unit) 
            throws InterruptedException, TimeoutException {
        long nanos = unit.toNanos(timeout);
        lock.lockInterruptibly();  // 可中断的获取锁
        try {
            // 等待直到有可用连接
            while (pool.isEmpty() && activeCount >= maxSize) {
                if (nanos <= 0) {
                    throw new TimeoutException();
                }
                nanos = notEmpty.awaitNanos(nanos);
            }
            
            Connection conn;
            if (!pool.isEmpty()) {
                conn = pool.removeFirst();
            } else {
                conn = createNewConnection();
                activeCount++;
            }
            return conn;
        } finally {
            lock.unlock();
        }
    }
    
    public void releaseConnection(Connection conn) {
        lock.lock();
        try {
            if (conn.isValid()) {
                pool.addLast(conn);
                notEmpty.signal();  // 通知等待的线程
            } else {
                activeCount--;
                notFull.signal();   // 通知可以创建新连接
            }
        } finally {
            lock.unlock();
        }
    }
}

场景3:读写锁模拟(业务特定场景)

public class ReadWriteResource {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition readCondition = lock.newCondition();
    private final Condition writeCondition = lock.newCondition();
    private int readers = 0;
    private boolean writing = false;
    private int writeRequests = 0;
    
    public void readLock() throws InterruptedException {
        lock.lock();
        try {
            while (writing || writeRequests > 0) {
                readCondition.await();
            }
            readers++;
        } finally {
            lock.unlock();
        }
    }
    
    public void readUnlock() {
        lock.lock();
        try {
            readers--;
            if (readers == 0) {
                writeCondition.signal();  // 通知写线程
            }
        } finally {
            lock.unlock();
        }
    }
    
    public void writeLock() throws InterruptedException {
        lock.lock();
        try {
            writeRequests++;
            while (writing || readers > 0) {
                writeCondition.await();
            }
            writeRequests--;
            writing = true;
        } finally {
            lock.unlock();
        }
    }
    
    public void writeUnlock() {
        lock.lock();
        try {
            writing = false;
            // 优先唤醒等待的写线程
            if (writeRequests > 0) {
                writeCondition.signal();
            } else {
                readCondition.signalAll();  // 唤醒所有读线程
            }
        } finally {
            lock.unlock();
        }
    }
}

场景4:批量任务处理器

public class BatchTaskProcessor {
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition batchReady = lock.newCondition();
    private final List<Task> batch = new ArrayList<>();
    private final int batchSize;
    private volatile boolean shutdown = false;
    
    public BatchTaskProcessor(int batchSize) {
        this.batchSize = batchSize;
    }
    
    public void addTask(Task task) throws InterruptedException {
        lock.lockInterruptibly();
        try {
            batch.add(task);
            
            // 批量达到阈值时通知处理器
            if (batch.size() >= batchSize) {
                batchReady.signal();
            }
        } finally {
            lock.unlock();
        }
    }
    
    public void processBatch() {
        lock.lock();
        try {
            // 等待批量任务准备就绪
            while (batch.size() < batchSize && !shutdown) {
                batchReady.await();
            }
            
            if (!batch.isEmpty()) {
                List<Task> currentBatch = new ArrayList<>(batch);
                batch.clear();
                
                // 释放锁后再执行耗时操作
                lock.unlock();
                try {
                    executeBatch(currentBatch);
                } finally {
                    lock.lock();
                }
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            lock.unlock();
        }
    }
}

场景5:分布式锁的本地优化

public class LocalCacheWithStampedLock {
    private final Map<String, CacheEntry> cache = new ConcurrentHashMap<>();
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition updateCondition = lock.newCondition();
    private volatile long lastUpdateTime = 0;
    private final long updateInterval;
    
    public LocalCacheWithStampedLock(long updateInterval) {
        this.updateInterval = updateInterval;
    }
    
    public Object get(String key) {
        CacheEntry entry = cache.get(key);
        
        // 乐观读:检查是否需要更新
        if (entry == null || 
            System.currentTimeMillis() - lastUpdateTime > updateInterval) {
            // 尝试升级为写锁
            return readWithUpdate(key);
        }
        return entry.getValue();
    }
    
    private Object readWithUpdate(String key) {
        // 使用 tryLock 避免阻塞
        if (lock.tryLock()) {
            try {
                // 双重检查
                CacheEntry entry = cache.get(key);
                if (entry == null || 
                    System.currentTimeMillis() - lastUpdateTime > updateInterval) {
                    // 执行更新
                    entry = loadFromDataSource(key);
                    cache.put(key, entry);
                    lastUpdateTime = System.currentTimeMillis();
                    updateCondition.signalAll();  // 通知其他等待线程
                }
                return entry.getValue();
            } finally {
                lock.unlock();
            }
        } else {
            // 获取不到锁,使用旧值
            CacheEntry entry = cache.get(key);
            return entry != null ? entry.getValue() : null;
        }
    }
}

七、高级特性与最佳实践

1. 锁的降级模式

public class LockDowngradeExample {
    private final ReentrantLock lock = new ReentrantLock();
    private volatile boolean dataValid = false;
    private Object data;
    
    public void writeThenRead() {
        lock.lock();  // 获取写锁
        try {
            // 写操作
            data = fetchData();
            dataValid = true;
            
            // 锁降级:在写锁内获取读锁
            lock.lock();  // 重入获取锁(读操作)
            try {
                // 读操作(仍在锁保护下)
                processData(data);
            } finally {
                lock.unlock();  // 释放读锁(但写锁仍持有)
            }
        } finally {
            lock.unlock();  // 释放写锁
        }
    }
}

2. 避免死锁的策略

public class DeadlockAvoidance {
    private final ReentrantLock lock1 = new ReentrantLock();
    private final ReentrantLock lock2 = new ReentrantLock();
    
    public void method1() {
        // 尝试获取锁,带有超时
        if (lock1.tryLock(100, TimeUnit.MILLISECONDS)) {
            try {
                Thread.sleep(50);  // 模拟工作
                if (lock2.tryLock(100, TimeUnit.MILLISECONDS)) {
                    try {
                        // 成功获取两把锁
                        doWork();
                    } finally {
                        lock2.unlock();
                    }
                } else {
                    // 获取第二把锁失败,回滚
                    rollback();
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock1.unlock();
            }
        }
    }
    
    // 使用锁排序避免死锁
    public void orderedLocking(Object obj1, Object obj2) {
        int hash1 = System.identityHashCode(obj1);
        int hash2 = System.identityHashCode(obj2);
        
        ReentrantLock firstLock = hash1 < hash2 ? lock1 : lock2;
        ReentrantLock secondLock = hash1 < hash2 ? lock2 : lock1;
        
        firstLock.lock();
        try {
            secondLock.lock();
            try {
                doWork();
            } finally {
                secondLock.unlock();
            }
        } finally {
            firstLock.unlock();
        }
    }
}

3. 性能监控与诊断

public class LockProfiler {
    private final ReentrantLock lock = new ReentrantLock(true);  // 公平锁用于调试
    private final ThreadLocal<Long> lockStartTime = new ThreadLocal<>();
    private final AtomicLong totalWaitTime = new AtomicLong();
    private final AtomicInteger lockCount = new AtomicInteger();
    
    public void performTask() {
        long startWait = System.nanoTime();
        lock.lock();
        try {
            long waitTime = System.nanoTime() - startWait;
            totalWaitTime.addAndGet(waitTime);
            lockCount.incrementAndGet();
            
            lockStartTime.set(System.nanoTime());
            // 执行业务逻辑
            doBusinessLogic();
            
            long holdTime = System.nanoTime() - lockStartTime.get();
            logLockMetrics(waitTime, holdTime);
        } finally {
            lock.unlock();
        }
    }
    
    public LockStats getStats() {
        return new LockStats(
            lockCount.get(),
            totalWaitTime.get() / lockCount.get(),
            lock.getQueueLength()  // 获取等待队列长度
        );
    }
}

八、与 synchronized 的对比

1. 功能对比表

特性 ReentrantLock synchronized
可重入性 ✅ 支持 ✅ 支持
公平锁 ✅ 可选择 ❌ 非公平
可中断 ✅ lockInterruptibly() ❌ 等待不可中断
尝试获取 ✅ tryLock() ❌ 不支持
超时机制 ✅ tryLock(timeout) ❌ 不支持
多条件变量 ✅ 多个Condition ❌ 单条件
锁绑定 ❌ 无 ✅ Object关联
性能 JDK6+优化后相当 JDK6+优化后相当

2. 选择建议

// 使用 synchronized 的情况:
// 1. 简单的同步场景
// 2. 需要与 wait/notify 配合
// 3. 不需要高级特性

// 使用 ReentrantLock 的情况:
// 1. 需要可中断的锁获取
// 2. 需要尝试获取锁(tryLock)
// 3. 需要公平锁
// 4. 需要多个条件变量
// 5. 需要锁的统计信息

九、常见问题与解决方案

Q1: 为什么 try-finally 中释放锁?

// ❌ 错误示例
lock.lock();
// 如果这里抛出异常,锁永远不会释放
doSomething();
lock.unlock();

// ✅ 正确示例
lock.lock();
try {
    doSomething();
} finally {
    lock.unlock();  // 确保锁被释放
}

Q2: 如何处理锁的嵌套?

public class NestedLockExample {
    private final ReentrantLock lock = new ReentrantLock();
    
    public void outerMethod() {
        lock.lock();
        try {
            innerMethod();  // 重入锁
        } finally {
            lock.unlock();
        }
    }
    
    public void innerMethod() {
        // 可重入,不会死锁
        lock.lock();
        try {
            // 内层逻辑
        } finally {
            lock.unlock();  // 释放内层锁
        }
    }
}

Q3: 如何避免锁泄漏?

public class LockLeakPrevention {
    private final ReentrantLock lock = new ReentrantLock();
    private final Set<Thread> lockHolders = ConcurrentHashMap.newKeySet();
    
    public void safeOperation() {
        if (!lock.tryLock()) {
            throw new IllegalStateException("锁被占用,可能发生泄漏");
        }
        
        try {
            lockHolders.add(Thread.currentThread());
            // 执行业务逻辑
            doOperation();
        } finally {
            lockHolders.remove(Thread.currentThread());
            lock.unlock();
        }
    }
    
    public void detectLeak() {
        if (lock.isLocked() && lockHolders.isEmpty()) {
            // 检测到锁泄漏:锁被占用但没有记录持有者
            handleLockLeak();
        }
    }
}

十、总结

ReentrantLock 核心优势:

  1. 灵活性:提供丰富的锁操作API

  2. 可扩展性:支持公平锁、条件变量等高级特性

  3. 诊断友好:可获取锁的状态信息

  4. 性能可控:在特定场景下可优化性能

适用场景:

  • 需要精确控制锁获取顺序的业务

  • 需要可中断锁操作的场景

  • 实现复杂的同步策略(如读写锁、批量处理)

  • 需要监控锁性能的应用

最佳实践:

  1. 始终在 try-finally 中释放锁

  2. 合理选择公平/非公平策略

  3. 优先使用 tryLock 避免死锁

  4. 监控锁的竞争情况,及时优化

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐