显式锁ReadWriteLock 和 ReentrantReadWriteLock

ReadWriteLock 也是一个接口,提供了readLock 和 writeLock 两种锁的操作。

package路径:java.util.locks.ReadWriteLock。

也就是:

一个资源能够被多个读线程访问,或者被一个写线程访问。但不能同时存在读写线程。

读写锁使用的场合:

一个共享资源被大量读取操作,而只有少量的写操作。

1 public interface ReadWriteLock {
2     
3     Lock readLock();
4     Lock writeLock();
5 }

 

ReadWriteLock 并不是 Lock 的子接口,只不过是借助Lock来实现读写两个锁并存、互斥的操作机制。

在ReadWriteLock中每次读取共享数据就需要读取锁,当需要修改共享数据时就需要写入锁。

 

ReentrantReadWriteLock 是 ReadWriteLock 在java.util里面唯一的实现类。读的时候并发的,写的时候是有顺序的带阻塞机制的。

主要应用场景是:

当很多线程都从某个数据结构中读取数据,而很少有线程对其修改时,在这种情况下,允许读取器线程共享访问是合适的。写入器线程必须是互斥的。

 

读写锁机制:

(1)读-读不互斥,10个线程去读(没有线程去写),这10个线程可以并发读,而不会堵塞。

(2)读-写互斥,当前写线程在使用的时候,读线程就会堵塞,反过来,有读线程在使用的时候,写的线程也会堵塞,看谁先拿到锁。

(3)写写互斥,写线程都是互斥的,如果2个线程去写,A线程先拿到先写,B就堵塞,直到A线程释放锁。

 

ReentrantReadWriteLock 是对 ReentrantLock的复杂扩展,能适合更加复杂的业务场景,ReentrantReadWriteLock可以实现一个方法中读写分离的锁的机制

而ReentrantLock加锁解锁只有一种机制。

 

ReentrantReadWriteLock对Lock又进行了扩展,引入了read和write阻塞和并发机制,相对于ReentrantLock,它可以实现更复杂的锁机制,且并发性也更高。

 

读写数据的场景:

 1 private final Map<String, Object> map = new HashMap<String, Objects>(); 
 2 // map 缓存了数据
 3 private final ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();
 4 
 5 public Object readWrite(String id) {
 6 
 7     Object value = null;
 8 
 9     rwlock.readLock().lock(); // 开读锁,从缓存中去获取
10 
11     try {
12 
13         value = map.get(id);
14 
15         if (value == null) {
16 
17             rwlock.readLock().unlock(); // 缓存中没有数据, 释放读锁, 上写锁。
18 
19             rwlock.writeLock().lock();
20 
21             try {
22 
23                 if (value == null) {
24                     value = "file"; // 数据库读取, 文件读取
25                 }
26 
27             } finally {
28                 rwlock.writeLock().unlock(); // 释放写锁
29             }
30 
31             rwlock.readLock().lock(); // 然后再上读锁
32         }
33 
34     } finally {
35         rwlock.readLock().unlock(); // 最后释放读锁
36     }
37 
38     return value;
39 }

 

posted @ 2017-12-26 18:18  晕菜一员  阅读(352)  评论(0编辑  收藏  举报