有比 ReadWriteLock更快的锁?( 五 )

我们来分析下这个方法 。
该方法会首先自旋的尝试获取读锁,获取成功后,就直接返回;否则,会将当前线程包装成一个读结点,插入到等待队列 。
由于,目前等待队列还是空,所以ThreadB会初始化队列,然后将自身包装成一个读结点,插入队尾,然后在下面这个地方跳出自旋:

有比 ReadWriteLock更快的锁?

文章插图
 
img
此时,等待队列的结构如下:
有比 ReadWriteLock更快的锁?

文章插图
 
img
跳出自旋后,ThreadB会继续向下执行,进入下一个自旋,在下一个自旋中,依然会再次尝试获取读锁,如果这次再获取不到,就会将前驱的等待状态置为WAITING, 表示我(当前线程)要去睡了(阻塞),到时记得叫醒我:
有比 ReadWriteLock更快的锁?

文章插图
 
img
有比 ReadWriteLock更快的锁?

文章插图
 
img
最终, ThreadB进入阻塞状态:
有比 ReadWriteLock更快的锁?

文章插图
 
最终,等待队列的结构如下:
有比 ReadWriteLock更快的锁?

文章插图
 
img
 五、StampedLock总结StampedLock的等待队列与RRW的CLH队列相比,有以下特点:
  1. 当入队一个线程时,如果队尾是读结点,不会直接链接到队尾,而是链接到该读结点的cowait链中,cowait链本质是一个栈;
  2. 当入队一个线程时,如果队尾是写结点,则直接链接到队尾;
  3. 唤醒线程的规则和AQS类似,都是首先唤醒队首结点 。区别是StampedLock中,当唤醒的结点是读结点时,会唤醒该读结点的cowait链中的所有读结点(顺序和入栈顺序相反,也就是后进先出) 。
另外,StampedLock使用时要特别小心,避免锁重入的操作,在使用乐观读锁时也需要遵循相应的调用模板,防止出现数据不一致的问题 。




推荐阅读