ReadWriteLock

如果是内部锁、可重入锁,在进行读操作、写操作时,是串行执行的
由于读操作不会对数据产生变更,所以这段串行等待时间可以优化。(读的耗时越多,读写锁的优势更明显)

  • 所以在“读-读”、或者“读大于写”的情况下加普通的锁就会影响性能
  • 读写锁用的是同一个 Sycn 同步器,因此等待队列、state 等也是同一个。因此读跟写是互斥的

使用注意事项

  • 读锁不支持条件变量
  • 重入时升级不支持:即持有读锁的情况下去获取写锁,会导致获取写锁永久等待

    1. class CachedData {
    2. Object data;
    3. // 是否有效,如果失效,需要重新计算 data
    4. volatile boolean cacheValid;
    5. final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    6. void processCachedData() {
    7. rwl.readLock().lock();
    8. if (!cacheValid) {
    9. // 获取写锁前必须释放读锁
    10. rwl.readLock().unlock();
    11. rwl.writeLock().lock();
    12. try {
    13. // 判断是否有其它线程已经获取了写锁、更新了缓存, 避免重复更新
    14. if (!cacheValid) {
    15. data = ...
    16. cacheValid = true;
    17. }
    18. // 降级为读锁, 释放写锁, 这样能够让其它线程读取缓存
    19. rwl.readLock().lock();
    20. } finally {
    21. rwl.writeLock().unlock();
    22. }
    23. }
    24. rw1.readLock().unlock();
    25. }
    26. }
  • 注意释放写锁是在获取读锁之后,反过来则不行