zoukankan      html  css  js  c++  java
  • 【Java多线程】ReentrantReadWriteLock

    概述

      ReentrantReadWriteLock是Lock的另一种实现方式,ReentrantLock是一个排他锁,同一时间只允许一个线程访问,而ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相对于排他锁,提高了并发性。在实际应用中,大部分情况下对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock能够提供比排他锁更好的并发性和吞吐量。

      所谓读写锁,是对访问资源共享锁和排斥锁,一般的重入性语义为 如果对资源加了写锁,其他线程无法再获得写锁与读锁,但是持有写锁的线程,可以对资源加读锁(锁降级);如果一个线程对资源加了读锁,其他线程可以继续加读锁。

      线程进入读锁的前提条件:

        没有其他线程的写锁,

        没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。

      线程进入写锁的前提条件:

        没有其他线程的读锁

        没有其他线程的写锁

    使用

      示例一:利用重入来执行升级缓存后的锁降级

    复制代码
     1 class CachedData {
     2     Object data;
     3     volatile boolean cacheValid;    //缓存是否有效
     4     ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
     5 
     6     void processCachedData() {
     7         rwl.readLock().lock();    //获取读锁
     8         //如果缓存无效,更新cache;否则直接使用data
     9         if (!cacheValid) {
    10             // Must release read lock before acquiring write lock
    11             //获取写锁前须释放读锁
    12             rwl.readLock().unlock();
    13             rwl.writeLock().lock();    
    14             // Recheck state because another thread might have acquired
    15             //   write lock and changed state before we did.
    16             if (!cacheValid) {
    17                 data = ...
    18                 cacheValid = true;
    19             }
    20             // Downgrade by acquiring read lock before releasing write lock
    21             //锁降级,在释放写锁前获取读锁
    22             rwl.readLock().lock();
    23             rwl.writeLock().unlock(); // Unlock write, still hold read
    24         }
    25 
    26         use(data);
    27         rwl.readLock().unlock();    //释放读锁
    28     }
    29 }
    复制代码

      示例二:使用 ReentrantReadWriteLock 来提高 Collection 的并发性

        通常在 collection 数据很多,读线程访问多于写线程并且 entail 操作的开销高于同步开销时尝试这么做。

    复制代码
     1 class RWDictionary {
     2     private final Map<String, Data> m = new TreeMap<String, Data>();
     3     private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
     4     private final Lock r = rwl.readLock();    //读锁
     5     private final Lock w = rwl.writeLock();    //写锁
     6 
     7     public Data get(String key) {
     8         r.lock();
     9         try { return m.get(key); }
    10         finally { r.unlock(); }
    11     }
    12     public String[] allKeys() {
    13         r.lock();
    14         try { return m.keySet().toArray(); }
    15         finally { r.unlock(); }
    16     }
    17     public Data put(String key, Data value) {
    18         w.lock();
    19         try { return m.put(key, value); }
    20         finally { w.unlock(); }
    21     }
    22     public void clear() {
    23         w.lock();
    24         try { m.clear(); }
    25         finally { w.unlock(); }
    26     }
    27 }
    复制代码

    实现原理

      ReentrantReadWriteLock 也是基于AQS实现的,它的自定义同步器(继承AQS)需要在同步状态(一个整型变量state)上维护多个读线程和一个写线程的状态,使得该状态的设计成为读写锁实现的关键。如果在一个整型变量上维护多种状态,就一定需要“按位切割使用”这个变量,读写锁将变量切分成了两个部分,高16位表示读,低16位表示写。

    转自:https://www.cnblogs.com/zaizhoumo/p/7782941.html,https://blog.csdn.net/prestigeding/article/details/53286756

  • 相关阅读:
    CSS 02
    CSS 01
    HTML 02
    SpringCloud学习(5)——Feign负载均衡
    SpringCloud学习(4)——Ribbon负载均衡
    SpringCloud学习(3)——Eureka服务注册中心及服务发现
    SpringCloud学习(2)——Rest微服务案例
    SpringCloud学习(1)——SpringCloud概述
    Spring 源码学习(4) —— 动态AOP使用示例
    Spring 源码学习(3) —— 增加属性注册编辑器
  • 原文地址:https://www.cnblogs.com/itplay/p/9962665.html
Copyright © 2011-2022 走看看