1、ReadWriteLock 简介
ReadWriteLock
在java.util.concurrent.locks包中定义了ReadWriteLock接口,该接口中定义了readLock()返回读锁,定义writeLock()方法返回写锁. 一个用于读操作(==readLock读锁==),一个用于写操作(==writeLock写锁==)。该接口的实现类是ReentrantReadWriteLock(可重入读写锁)。
线程在读取共享数据前必须先持有读锁,该读锁可以同时被多个线程持有,即它是共享的。线程在修改共享数据前必须先持有写锁,写锁是排他的(独占锁),一个线程持有写锁时其他线程无法获得相应的锁。
读锁只是在读线程之间共享,任何一个线程持有读锁时,其他线程都无法获得写锁, 保证线程在读取数据期间没有其他线程对数据进行更新,使得读线程能够读到数据的最新值,保证在读数据期间共享变量不被修改。
读写锁允许:
- 读读共享:读 - 读操作可以共存
- 读写互斥:读 - 写操作不能共存
- 写写互斥:写 - 写操作不能共存

2、ReadWriteLock 使用
模拟缓存数据的写入和读取
不加读写锁的情况
package com.cheng.rw;
import java.util.HashMap;
import java.util.Map;
public class ReadWriteLock {
public static void main(String[] args) {
MyCache myCache = new MyCache();
//写操作
for (int i = 0; i < 5; i++) {
final int temp = i;
new Thread(()->{
myCache.set(temp+"",temp+"");
},String.valueOf(i)).start();
}
//读操作
for (int i = 0; i < 5; i++) {
final int temp = i;
new Thread(()->{
myCache.get(temp+"");
},String.valueOf(i)).start();
}
}
}
class MyCache{
private volatile Map<String,Object> map = new HashMap<>();
//写操作
public void set(String key,Object value){
System.out.println(Thread.currentThread().getName()+"写入了"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入操作完成");
}
//读操作
public void get(String key){
System.out.println(Thread.currentThread().getName()+"读取了"+key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取操作完成");
}
}
运行查看结果:

不加读写锁,当前线程在进行写入操作时被其他线程插队。
加上读写锁
package com.cheng.rw;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class ReadWriteLock {
public static void main(String[] args) {
MyCacheLock myCache = new MyCacheLock();
//写操作
for (int i = 0; i < 5; i++) {
final int temp = i;
new Thread(()->{
myCache.set(temp+"",temp+"");
},String.valueOf(i)).start();
}
//读操作
for (int i = 0; i < 5; i++) {
final int temp = i;
new Thread(()->{
myCache.get(temp+"");
},String.valueOf(i)).start();
}
}
}
class MyCacheLock{
private volatile Map<String,Object> map = new HashMap<>();
private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();//定义读写锁
//写操作
public void set(String key,Object value){
readWriteLock.writeLock().lock();//加上写锁
try {
System.out.println(Thread.currentThread().getName()+"写入了"+key);
map.put(key,value);
System.out.println(Thread.currentThread().getName()+"写入操作完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.writeLock().unlock();//释放写锁
}
}
//读操作
public void get(String key){
readWriteLock.readLock().lock();//加上读锁
try {
System.out.println(Thread.currentThread().getName()+"读取了"+key);
Object o = map.get(key);
System.out.println(Thread.currentThread().getName()+"读取操作完成");
} catch (Exception e) {
e.printStackTrace();
} finally {
readWriteLock.readLock().unlock();//释放读锁
}
}
}
运行查看结果:

写操作一次只允许一条线程执行,读操作可以多条线程同时执行。
3、读写锁比其他锁的优势
synchronized内部锁与ReentrantLock锁都是独占锁(排它锁), 同一时间只允许一个线程执行同步代码块,可以保证线程的安全性,但是执行效率低。
ReentrantReadWriteLock读写锁是一种改进的排他锁,也可以称作共享/排他锁. 允许多个线程同时读取共享数据,可以提高程序的读取数据的效率,但是一次只允许一个线程对共享数据进行更新。
ReentrantReadWriteLock 更细粒度的控制对资源的读写。
作者:万里顾一程
链接:https://juejin.cn/post/7013533087598379044
来源:稀土掘金
网友评论