读写锁

  • 读读并发
  • 读写互斥
  • 写写互斥


读写锁读锁不支持条件

  1. 读锁的条件直接调用ReentrantReadWriteLock newCondition 会直接exception
  2. public Condition newCondition() {
  3. throw new UnsupportedOperationException();
  4. }

读写锁使用的例子

package com.shadow.lock;
import com.shadow.aqs.CustomSync;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.*;
@Slf4j(topic = "enjoy")
public class LockTest10 {
      static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
      static Lock r = rwl.readLock();
      static Lock w = rwl.writeLock();
    public static void main(String[] args) throws InterruptedException {
        //读
        new Thread(()->{
            log.debug("read 获取 锁");
            r.lock();
            try {
                for (int i = 0; i < 10; i++) {
                    m1(i);
                }
            }finally {
                r.unlock();
            }
        },"t1").start();


        //写
        new Thread(()->{
            log.debug("write 获取 锁");
            w.lock();
            try {
                for (int i = 0; i < 20; i++) {
                    m1(i);
                }
            }finally {
                w.unlock();
            }
        },"t2");


        //读
        new Thread(()->{
            log.debug("write 获取 锁");
            r.lock();
            try {
                for (int i = 0; i < 20; i++) {
                    m1(i);
                }
            }finally {
                r.unlock();
            }
        },"t3").start();
    }
    public static void m1(int i){
            log.debug("exe"+i);
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

读写支持重入 但是只支持降级不支持升级 (写锁里面再获取读锁),否则会一直阻塞

package com.shadow.lock;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
@Slf4j(topic = "enjoy")
public class LockTest11 {
      static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
      static Lock r = rwl.readLock();
      static Lock w = rwl.writeLock();
    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            log.debug("read");
            w.lock();
            try {
                log.debug("read 已经获取");
                r.lock();
                log.debug("write 已经获取");
            } finally {
                r.unlock();
                w.unlock();
            }
        }, "t1").start();
    }
}
//缓存
class CachedData {
    Object data;
    //判断缓存是否过期
    volatile boolean cacheValid;
    //定义一把读写锁
    final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    //处理缓存的方法
     void processCachedData() {
      rwl.readLock().lock();
      //如果缓存没有过期则调用 use(data);
      if (!cacheValid) {//要去load真实数据   set给缓存拿到写锁
        //释放读锁 因为不支持升级 所以需要先释放  
        rwl.readLock().unlock();          
        rwl.writeLock().lock();
        try {
          //双重检查
          if (!cacheValid) {
            data = "数据库得到真实数据"
            cacheValid = true;
          }

          //更新缓存之后接着读取 所以先加锁
          rwl.readLock().lock();
        } finally {
          rwl.writeLock().unlock(); // Unlock write, still hold read
        }
      }

      try {
          //不管上面的if进不进都会执行这里
        //缓存可用  
        use(data);
      } finally {
        rwl.readLock().unlock();
      }
    }
  }
}

为什么读写锁不能升级只能降级?

假如支持升级

线程t1 请求读锁
线程t2 请求读锁
线程t3 请求写锁
这时候三个线程都拿到锁了
t1执行完然后去请求写锁,因为读写互斥,所以t1 会等待 t2 和t3 执行完才能去拿到写锁
这时候t2 执行完请求写锁,t2 也会去等待t1 和t3 执行完
所以t1 和 t2 就产生了死锁。