持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
在开发过程中,遇到了读的操作很多,但是写的操作很少,这时候我们再去对读操作和写操作都加锁,这时候对·读操作再加上锁就会显得多余。这是我们需要采用新的锁-----读写锁
含义
读写锁顾名思义是一把锁分为两部分:读锁和写锁,其中读锁允许多个线程同时获得,因为读操作本身是线程安全的,而写锁则是互斥锁,不允许多个线程同时获得写锁,并且写操作和读操作也是互斥的。总结来说,读写锁的特点是:读读不互斥、读写互斥、写写互斥。
读写锁可以保证在没有写入操作的时候,多个线程允许同时读取来提高性能。
常用的两种读写锁
ReentrantReadWriteLock可重入锁Java8下面的StampedLock不可重入锁
对比StampedLock
ReentrantReadWriteLock 存在一个问题就是读锁是一个悲观锁,如果又线程真在进行读操作,写线程需要等待读线程释放锁后才能获取写锁,就是读的过程中中是不允许写入的。他是一个可重入锁,可以在一个线程中反复获取同一个锁。
StampedLock的好处就是在读的过程中允许进行写入操作,但在读的的过程进行写入后就需要判断读的时候是否有写入,来保证数据的一致性,所以StampedLock的读锁是一种乐观锁。乐观锁即通过版本号来控制读的过程中是否有写入操作。他是一个不可重入锁,不能在一个线程中反复获取同一个锁。
StampedLock还提供了更复杂的将悲观读锁升级为写锁的功能,它主要使用在if-then-update的场景:即先读,如果读的数据满足条件,就返回,如果读的数据不满足条件,再尝试写。
- long tryConvertToWriteLock(long stamp) 转换为写锁(锁升级)
- long tryConvertToReadLock(long stamp)转换为读锁(锁降级)
- long tryConvertToOptimisticRead(long stamp)
下面编写代码演示StampedLock的使用
public class StampedLockTest {
private final StampedLock stampedLock = new StampedLock();
private double x = 1.0;
// 写锁
public void add() throws InterruptedException {
// 版本号
long stamp = stampedLock.writeLock();
System.out.println("获取了写锁"+stamp);
Thread.sleep(500);
try {
x = x + 12.0;
} finally {
stampedLock.unlock(stamp);
System.out.println("写锁释放"+stamp);
}
}
// 读锁
public double read() throws InterruptedException {
// 获得一个乐观锁版本号
long stamp = stampedLock.tryOptimisticRead();
System.out.println("获取了读锁"+stamp);
Thread.sleep(1000);
double y = x;
// 验证是否有写锁,即版本号是否发生变化
if (!stampedLock.validate(stamp)) {
System.out.println("两次版本号不一致");
long lock = stampedLock.readLock();
try {
y = x;
} finally {
stampedLock.unlockRead(lock);
}
}
return y;
}
public static void main(String[] args) {
StampedLockTest lockTest = new StampedLockTest();
Thread add = new Thread(() -> {
try {
lockTest.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread read = new Thread(() -> {
try {
lockTest.read();
add.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
read.start();
add.start();
}
}
从结果分析可以看出
程序先获取了读锁,在写线程执行完成后版本后发生了变化,所以可以进入if()判断语句。即实现了在读锁的同时可以获的写锁来进行操作。
总结
StampedLock不能完成替代ReentrantReadWriteLock
`StampedLock`不支持公平锁,也不支持Condition
StampedLock不可重入