ReentrantReadWriteLock 和 ReentrantLock 的联系与区别

相同点

  1. 可重入性

    • 两者都支持可重入,同一线程可以多次获取相同的锁
    • 都维护着获取锁的次数计数器
  2. 公平性策略

    • 都支持公平锁和非公平锁模式
    • 构造函数都可以指定是否采用公平策略
  3. 底层实现

    • 都基于 AbstractQueuedSynchronizer(AQS)框架实现
    • 都支持中断响应和超时获取锁
  4. 内存语义

    • 都提供与 synchronized 相同的内存可见性保证
    • 释放锁前的写操作对后续获取锁的线程可见

不同点

1. 锁的类型和并发特性

特性 ReentrantLock ReentrantReadWriteLock
锁类型 独占锁(排他锁) 读写分离锁
读读并发 不支持 支持
读写并发 不支持 不支持
写写并发 不支持 不支持
适用场景 一般互斥访问 读多写少场景

2. 获取锁的方式

// ReentrantLock
ReentrantLock lock = new ReentrantLock();
lock.lock();
try {
    // 临界区代码
} finally {
    lock.unlock();
}

// ReentrantReadWriteLock
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
// 获取读锁
rwLock.readLock().lock();
try {
    // 读操作
} finally {
    rwLock.readLock().unlock();
}

// 获取写锁
rwLock.writeLock().lock();
try {
    // 写操作
} finally {
    rwLock.writeLock().unlock();
}

3. 性能特征

  • ReentrantLock: 适合读写频率相当或以写为主的场景
  • ReentrantReadWriteLock: 适合读操作远多于写操作的场景,可以显著提高读并发性能

4. 复杂度和开销

  • ReentrantLock: 实现简单,开销较小
  • ReentrantReadWriteLock: 实现复杂,有额外的状态管理和开销

5. 锁降级支持

// ReentrantReadWriteLock 支持锁降级(写锁降级为读锁)
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

rwLock.writeLock().lock();
try {
    // 执行写操作
    String data = updateData();
    
    // 锁降级:在持有写锁的情况下获取读锁
    rwLock.readLock().lock();
    try {
        // 使用新数据
        useData(data);
    } finally {
        // 释放写锁,保留读锁
        rwLock.writeLock().unlock();
    }
    // 继续使用读锁
} finally {
    rwLock.readLock().unlock();
}

6. 条件变量支持

  • ReentrantLock: 支持多个 Condition 对象
  • ReentrantReadWriteLock: 只有写锁支持 Condition,读锁不支持

选择建议

选择 ReentrantLock 的场景:

  • 一般的互斥访问控制
  • 读写操作频率相近
  • 对性能要求较高且不需要读写分离

选择 ReentrantReadWriteLock 的场景:

  • 读操作远多于写操作(80%以上读操作)
  • 需要提高读并发性能
  • 数据一致性要求高且读频繁的场景

总结

ReentrantReadWriteLock 可以看作是 ReentrantLock 的扩展版本,专门针对读写分离场景进行了优化。两者都提供了比 synchronized 更强大的功能,但在具体应用场景上有明确的分工。选择哪种锁取决于具体的并发访问模式和性能要求。

posted @ 2025-11-28 14:02  yub4by  阅读(5)  评论(0)    收藏  举报