概念:
ReentrantLock的增强版本,内部维护了一对读写锁,适用于读多写少的场景。
特性:
带有锁饥饿的问题,一旦读操作比较多的时候,想要获取写锁就变得比较困难。
可以进行锁降级,由写锁过渡到读锁,可以 增强数据的可见性,减少读锁阻塞的情况。
ReentrantReadWriteLock和ReentrantLock的性能对比:
可以看到ReentrantReadWriteLock在读多写少的场景下的性能提升不是一点半点。
**
* @author maoyouhua
* @version jdk21
*/
public class ReentrantReadWriteLockDemo {
private int number = 0;
private final ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
private final ReentrantLock readWriteLock = new ReentrantLock();
public void lockRead(){
readWriteLock.lock();
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
readWriteLock.unlock();
}
public void lockWrite(int incr){
readWriteLock.lock();
number += incr;
try {
TimeUnit.MILLISECONDS.sleep(30);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
readWriteLock.unlock();
}
public void readWriteLockRead(){
reentrantReadWriteLock.readLock().lock();
try {
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
reentrantReadWriteLock.readLock().unlock();
}
public void readWriteLockWrite(int incr){
reentrantReadWriteLock.writeLock().lock();
number += incr;
try {
TimeUnit.MILLISECONDS.sleep(30);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
reentrantReadWriteLock.writeLock().unlock();
}
/**
* ReentrantLock执行时间是:17229
* ReentrantReadWriteLock执行时间是:1705
*/
public static void main(String[] args) throws InterruptedException {
int readSize = 1000;
int writeSize = 50;
var demo = new ReentrantReadWriteLockDemo();
var read = new CountDownLatch(readSize);
var write = new CountDownLatch(writeSize);
var readWriteLockRead = new CountDownLatch(readSize);
var readWriteLockWrite = new CountDownLatch(writeSize);
long start = System.currentTimeMillis();
for (int i = 0; i < writeSize; i++) {
new Thread(() ->{
demo.lockWrite(1);
write.countDown();
},"Thread - write -" + i).start();
}
for (int i = 0; i < readSize; i++) {
new Thread(() ->{
demo.lockRead();
read.countDown();
},"Thread - read -" + i).start();
}
read.await();
write.await();
long end = System.currentTimeMillis();
System.out.println("ReentrantLock执行时间是:" + (end - start));
System.out.println(demo.number);
start = System.currentTimeMillis();
for (int i = 0; i < writeSize; i++) {
new Thread(() ->{
demo.readWriteLockWrite(1);
readWriteLockWrite.countDown();
},"Thread - write -" + i).start();
}
for (int i = 0; i < readSize; i++) {
new Thread(() ->{
demo.readWriteLockRead();
readWriteLockRead.countDown();
},"Thread - read -" + i).start();
}
readWriteLockRead.await();
readWriteLockWrite.await();
end = System.currentTimeMillis();
System.out.println("ReentrantReadWriteLock执行时间是:" + (end - start));
System.out.println(demo.number);
}
}