1、StampedLock是做什么的?
-----》它是ReentrantReadWriteLock 的增强版,是为了解决ReentrantReadWriteLock的一些不足。
2、ReentrantReadWriteLock有什么不足之处呢?
------》我们都知道,ReentrantReadWriteLock是读写锁,在多线程环境下,大多数情况是读的情况远远大于写的操作,因此可能导致写的饥饿问题。(换人话来说的话,读操作一直都能抢占到CPU时间片,而写操作一直抢不了)
3、为什么会导致写操作会出血饥饿问题呢?
-----》ReentrantReadWriteLock写锁的互斥的
(读和读---不互斥,读和写---互斥,写和写----互斥),懂了吗?
4、正因为ReentrantReadWriteLock出现了读和写是互斥的情况,这个地方需要优化,因此就出现了StampedLock!
5、StampedLock是读锁并不会阻塞写锁。这里就有朋友会问,如果这样设计的话,那么怎样保证读和写的一致性呢?
-----》StampedLock的设计思路也比较简单,就是在读的时候发现有写操作,再去读多一次。(思想上来说)
6、那下一个问题就是StampedLock是怎样知道读的时候发生了写操作呢?
-----》我们的StampedLock有两种锁,一种是悲观锁,另外一种是乐观锁。如果线程拿到乐观锁就读和写不互斥,如果拿到悲观锁就读和写互斥。
7、看StampedLock源码的时候,可以看writeLock()和trywriteLock(),tryOptimisticRead()这是本API中最有亮点的方法(乐观锁)。
==============================================================
public class Demo {
private int balance;
private StampedLock lock = new StampedLock();
public void conditionReadWrite (int value) {
// 首先判断balance的值是否符合更新的条件
long stamp = lock.readLock();
while (balance > 0) {
long writeStamp = lock.tryConvertToWriteLock(stamp);
if(writeStamp != 0) { // 成功转换成为写锁
stamp = writeStamp;
balance += value;
break;
} else {
// 没有转换成写锁,这里需要首先释放读锁,然后再拿到写锁
lock.unlockRead(stamp);
// 获取写锁
stamp = lock.writeLock();
}
}
lock.unlock(stamp);
}
public void optimisticRead() {
long stamp = lock.tryOptimisticRead();
int c = balance;
// 这里可能会出现了写操作,因此要进行判断
if(!lock.validate(stamp)) {
// 要从新读取
long readStamp = lock.readLock();
c = balance;
stamp = readStamp;
}
///
lock.unlockRead(stamp);
}
public void read () {
long stamp = lock.readLock();
lock.tryOptimisticRead();
int c = balance;
// ...
lock.unlockRead(stamp);
}
public void write(int value) {
long stamp = lock.writeLock();
balance += value;
lock.unlockWrite(stamp);
}
}
====================================================
StampedLock的性能是远远好过ReentrantReadWriteLock的。那为什么还存在ReentrantReadWriteLock呢?
------》根据我们上述的代码,我们知道使用StampedLock,编写代码上相对繁琐些。ReentranReadWriteLock比较简单些。
悲观锁:每次拿数据的时候就去锁上。
乐观锁:每次去拿数据的时候,都没锁上,而是判断标记位是否有被修改,如果有修改就再去读一次。
(就像很多个人去桌子上看今天老师布置的作业题,另外桌子旁边有一个牌子,红色面代表“作业题已经被修改过了”,白色面代表“题目是最新的”。第一个人去看作业题,再看了下牌子,牌子是白色的,作业题是最新的。但是有一个人去看作业题,看完之后,再看隔壁的牌子,牌子变成红色了,于是他赶紧回去看了一下题目,果然题目已经被改过了,于是他再看了一次,再确认一次牌子颜色,都没问题之后,就放心走了。)