• 怎样用读写锁快速实现一个缓存?


    1)SDK已经有管程了,不是可以解决所有的并发问题的吗,为什么还要有读写锁?

    • 不同的场景下使用不同的锁效果是不一样的,我们的读写锁用在读多写少的场景下那是非常有用的。

    2)读写锁是我们JAVA特有的吗?他有什么原则?

    • 读写锁并不是java特有的,是通用的一个技术方案。读写锁的话有三个基本原则:

      • 同一时刻,允许多个线程去读一个变量

      • 同一时刻,只允许一个线程去写变量

      • 当有一个线程在写变量的时候,是不能读的

    3)读写锁在java中是怎样实现的,怎样使用?

    • ReadWriteLock他只是一个接口,他的实现子类是ReentrantReadWriteLock。

    • 用的时候直接调用读锁或者写锁readLock()

    4)既然说了读写锁适合我们缓存的场景下的使用,那读写锁怎样快速的实现一个缓存呢?

    • 我们定义一个类,这个类呢有k 和 v变量,代表缓存的key和value。有get()读方法,和put()写方法。读的时候上读锁,写的时候上写锁。

       class Cache<K,V> {
         final Map<K, V> m =
           new HashMap<>();
         final ReadWriteLock rwl =
           new ReentrantReadWriteLock();
         // 读锁
         final Lock r = rwl.readLock();
         // 写锁
         final Lock w = rwl.writeLock();
         // 读缓存
         V get(K key) {
           r.lock();
           try { return m.get(key); }
           finally { r.unlock(); }
        }
         // 写缓存
         V put(K key, V value) {
           w.lock();
           try { return m.put(key, v); }
           finally { w.unlock(); }
        }
       }

    5)实现缓存,会存在数据初始化的问题,那么我们缓存里面的数据该怎样初始化呢?

    • 对于数据比较少的,我们直接一次性把数据装进缓存,简单粗暴又高效。

    • 对于数据比较多的,要读数据的时候,我们再把它存进缓存里面来。

    6)上面实现初始化缓存数据的的方法中,第二种代码是怎样实现的?

     
     class Cache<K,V> {
       final Map<K, V> m =
         new HashMap<>();
       final ReadWriteLock rwl =
         new ReentrantReadWriteLock();
       final Lock r = rwl.readLock();
       final Lock w = rwl.writeLock();
     
       V get(K key) {
         V v = null;
         //读缓存
         r.lock();        
         try {
           v = m.get(key);
        } finally{
           r.unlock();    
        }
         //缓存中存在,返回
         if(v != null) {  
           return v;
        }  
         //缓存中不存在,查询数据库
         w.lock();        
         try {
           //再次验证
           //其他线程可能已经查询过数据库
           v = m.get(key);
           if(v == null){  
             //查询数据库
             v=省略代码无数
             m.put(key, v);
          }
        } finally{
           w.unlock();
        }
         return v;
      }
     }

    7)为什么要再次进行验证?

    • 因为我们的读是并发的,不确定其它线程在这个期间读过没有,为了防止重复读,所以要再次验证。

    注意:我们的读写锁是可以升级和降级的。但是java中是不可以升级的,升级的话会造成死锁的现象发生。

  • 相关阅读:
    Canvas 基本绘图方法总结
    js: 从setTimeout说事件循环模型
    HTML5 表单元素
    jQuery选择器
    jQuery基本动画
    HangFire循环作业中作业因执行时间太长未完成新作业开启导致重复数据的问题
    .net 上传文件 Failed to load resource: net::ERR_CONNECTION_RESET Bug 解决
    ABP Zero项目入门踩坑
    关于toggle事件委托的处理
    关于height,line-height导致的样式混乱的问题
  • 原文地址:https://www.cnblogs.com/YXBLOGXYY/p/16068373.html
Copyright © 2020-2023  润新知