StampedLock

来源:6-6 J.U.C之AQS-ReentrantLock与锁-2

红邮筒

2019-02-21

老师,关于StampedLock有几个问题麻烦您解答:
1、是不是只有在写锁未被占用时才能获取乐观读锁?在悲观读锁被占用是也可以获取乐观读锁?而在其他线程占用乐观读锁的情况下可以获取写锁或悲观读锁?
2、当有线程获取写锁时,其他线程请求写锁会被阻塞,加入Wnode的队列,此时如果有其他线程请求悲观读锁,如图,它是Wnode节点还是cowait节点
图片描述

写回答

1回答

Jimin

2019-02-21

你好,

1、以下是关于StampedLock涉及到锁的标准说明:

写锁writeLock,是个排它锁或者叫独占锁,同时只有一个线程可以获取该锁,当一个线程获取该锁后,其它请求的线程必须等待,当目前没有线程持有读锁或者写锁的时候才可以获取到该锁,请求该锁成功后会返回一个stamp票据变量用来表示该锁的版本,当释放该锁时候需要unlockWrite并传递参数stamp。

悲观读锁readLock,是个共享锁,在没有线程获取独占写锁的情况下,同时多个线程可以获取该锁,如果已经有线程持有写锁,其他线程请求获取该读锁会被阻塞。这里讲的悲观其实是参考数据库中的乐观悲观锁的,这里说的悲观是说在具体操作数据前悲观的认为其他线程可能要对自己操作的数据进行修改,所以需要先对数据加锁,这是在读少写多的情况下的一种考虑,请求该锁成功后会返回一个stamp票据变量用来表示该锁的版本,当释放该锁时候需要unlockRead并传递参数stamp

乐观读锁tryOptimisticRead,是相对于悲观锁来说的,在操作数据前并没有通过CAS设置锁的状态,如果当前没有线程持有写锁,则简单的返回一个非0的stamp版本信息,获取该stamp后在具体操作数据前还需要调用validate验证下该stamp是否已经不可用,也就是看当调用tryOptimisticRead返回stamp后到到当前时间间是否有其他线程持有了写锁,如果是那么validate会返回0,否者就可以使用该stamp版本的锁对数据进行操作。由于tryOptimisticRead并没有使用CAS设置锁状态所以不需要显示的释放该锁。该锁的一个特点是适用于读多写少的场景,因为获取读锁只是使用与或操作进行检验,不涉及CAS操作,所以效率会高很多,但是同时由于没有使用真正的锁,在保证数据一致性上需要拷贝一份要操作的变量到方法栈,并且在操作数据时候可能其他写线程已经修改了数据,而我们操作的是方法栈里面的数据,也就是一个快照,所以最多返回的不是最新的数据,但是一致性还是得到保障的

2、感觉你学的很深入,但问的问题又特别的基础(没有这些基础根本无法理解源码),有点看不出你到底学的是很深入还是很表面,cowait是专门用于链接等待读的线程队列

祝你学习愉快~

0
6
Jimin
如果进课程学习群了,在群里单独找一下我吧,我们单独聊一下,聊聊关于源码学习及学习源码的方法,我感觉你自己额外学了不少,但不够高效,担心你做一些无用功
2019-02-22
共6条回复

Java高并发编程,构建并发知识体系,提升面试成功率

构建完整并发与高并发知识体系,倍增高薪面试成功率!

3923 学习 · 832 问题

查看课程