【Java多线程】ReentrantReadWriteLock

java

概述

  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位表示写。

以上是 【Java多线程】ReentrantReadWriteLock 的全部内容, 来源链接: utcz.com/z/390935.html

回到顶部