• java中的读/写锁


    读写锁接口:ReadWriteLock,它的具体实现类为:ReentrantReadWriteLock

    使用场景:

    对于一个资源,读读能共存,读写不能共存,写写不能共存。

    锁降级:从写锁变成读锁;

    锁升级:从读锁变成写锁。

    ReentrantReadWriteLock不支持锁升级,支持锁降级

    ReadWriteLock rtLock = new ReentrantReadWriteLock();
     rtLock.readLock().lock();
     System.out.println("get readLock.");
     rtLock.writeLock().lock();
     System.out.println("blocking");

    会死锁

    ReadWriteLock rtLock = new ReentrantReadWriteLock();
    rtLock.writeLock().lock();
    System.out.println("writeLock");
    
    rtLock.readLock().lock();
    System.out.println("get read lock");

    不会死锁

    案例应用:

    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    public class CacheDemo {
        /**
         * 缓存器,这里假设需要存储1000左右个缓存对象,按照默认的负载因子0.75,则容量=750,大概估计每一个节点链表长度为5个
         * 那么数组长度大概为:150,又有雨设置map大小一般为2的指数,则最近的数字为:128
         */
        private Map<String, Object> map = new HashMap<>(128);
        private ReadWriteLock rwl = new ReentrantReadWriteLock();
        public static void main(String[] args) {
    
        }
        public Object get(String id){
            Object value = null;
            rwl.readLock().lock();//首先开启读锁,从缓存中去取
            try{
                value = map.get(id);
                if(value == null){  //如果缓存中没有释放读锁,上写锁
                    rwl.readLock().unlock();
                    rwl.writeLock().lock();
                    try{
                        if(value == null){ //防止多写线程重复查询赋值
                            value = "redis-value";  //此时可以去数据库中查找,这里简单的模拟一下
                        }
                        rwl.readLock().lock(); //加读锁降级写锁,不明白的可以查看上面锁降级的原理与保持读取数据原子性的讲解
                    }finally{
                        rwl.writeLock().unlock(); //释放写锁
                    }
                }
            }finally{
                rwl.readLock().unlock(); //最后释放读锁
            }
            return value;
        }
    }

    如果不使用锁降级功能,如先释放写锁,然后获得读锁,在这个get过程中,可能会有其他线程竞争到写锁 或者是更新数据 则获得的数据是其他线程更新的数据,可能会造成数据的污染,即产生脏读的问题。

  • 相关阅读:
    SpringBoot整合Swagger2
    AuthenticationToken的元素不满足实际情况,登录的时候需要有学校id或者其他参数
    nginx导入学成静态网页
    springboot使用枚举类型
    springboot配置多个yml文件
    尝试使用freemarker模板引擎生成打印文件
    多版本并发控制 MVCC 实现可重复读
    多版本并发控制 MVCC简介
    模拟3级分类信息查询
    IDEA去掉屏幕中间的白色竖线
  • 原文地址:https://www.cnblogs.com/L-a-u-r-a/p/8569749.html
Copyright © 2020-2023  润新知