概述
ReentrantReadWriteLock,是一种读写锁,对读写操作的多线程访问提供了特殊处理,可以提高读取操作的性能,让读并发,写加锁。
- 读操作可并发
- 读写操作互斥
- 写操作互斥
其原理与ReentrantLock基本一直,只不过加入了读写锁的逻辑,底层也是使用了AQS同步器,AQS的源码解析可查阅我的另一篇文章:Java多线程——JUC之AQS(AbstractQueuedSynchronizer)分析,ReentrantLock的实现原理解析
基本使用
package com.leolee.multithreadProgramming.juc.reentrantReadWriteLock;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* @ClassName Test
* @Description: reentrantReadWriteLock,读写锁,可以提高读取操作的性能,让读并发,写加锁
* @Author LeoLee
* @Date 2021/3/7
* @Version V1.0
**/
@Slf4j
public class Test {
public static void main(String[] args) {
Test.test2();
}
/*
* 功能描述: <br>
* 〈验证读写锁——多线程【读】操作是否互斥〉
* 结果:读写锁的读操作是不互斥的
* @Param: []
* @Return: void
* @Author: LeoLee
* @Date: 2021/3/7 13:55
*/
public static void test1() {
ReadWriteLock readWriteLock = new ReadWriteLock();
new Thread(() -> {
readWriteLock.read();
}, "t1").start();
new Thread(() -> {
readWriteLock.read();
}, "t2").start();
}
/*
* 功能描述: <br>
* 〈验证读写锁——多线程【读写】操作是否互斥〉
* 结果:读写锁的读写操作是互斥的
* @Param: []
* @Return: void
* @Author: LeoLee
* @Date: 2021/3/7 13:55
*/
public static void test2() {
ReadWriteLock readWriteLock = new ReadWriteLock();
new Thread(() -> {
readWriteLock.read();
}, "t1").start();
new Thread(() -> {
readWriteLock.write();
}, "t2").start();
}
}
@Slf4j
class ReadWriteLock {
private Object data;
private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
//读锁
private ReentrantReadWriteLock.ReadLock readLock = rwl.readLock();
//写锁
private ReentrantReadWriteLock.WriteLock writeLock = rwl.writeLock();
public Object read() {
log.info("获取读锁...");
readLock.lock();
try {
log.info("读取操作");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} finally {
log.info("释放读锁...");
readLock.unlock();
}
return data;
}
public void write() {
log.info("获取写锁...");
writeLock.lock();
try {
log.info("写入操作");
} finally {
log.info("释放写锁...");
writeLock.unlock();
}
}
}
注意事项:
- 读锁不支持条件变量,也就是无法使用Condition。
- ReentrantReadWriteLock是可重入锁,但是不支持重入的锁升级,即有读锁的情况下去获取写锁,会导致获取写锁永久等待,发生死锁。在持有写锁的情况下,是可以支持获取读锁的。
Javadoc关于重入情况下,写锁降级为读锁的示例
* <pre> {@code
* class CachedData {
* Object data;
* volatile boolean cacheValid;
* final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
*
* void processCachedData() {
* rwl.readLock().lock();
* if (!cacheValid) {
* // Must release read lock before acquiring write lock
* rwl.readLock().unlock();
* rwl.writeLock().lock();
* try {
* // Recheck state because another thread might have
* // acquired write lock and changed state before we did.
* if (!cacheValid) {
* data = ...
* cacheValid = true;
* }
* // Downgrade by acquiring read lock before releasing write lock
* rwl.readLock().lock();
* } finally {
* rwl.writeLock().unlock(); // Unlock write, still hold read
* }
* }
*
* try {
* use(data);
* } finally {
* rwl.readLock().unlock();
* }
* }
* }}</pre>