获取写锁加1操作就比较简单了,因为写锁是独占锁,与正常的ReentrantLock获取锁实现一样,占用state的低16位表示,不用看state的高16,左边补16位0。获取写锁一次,直接 c+1;
2、一个线程获取到读锁:
state =65536, w= 0, r=1
c初始为0 ,获取读锁,则读锁数量+1,执行 c + SHARED_UNIT, SHARED_UNIT = (2)1000000000000000 = (10)65536,括号内表示进制,SHARED_UNIT是每次读锁加1的数值。
如下图所示: 在获取读锁数量 r时,将state的低16位抹去,r=1,而state此时的值= 2^16 =65536,state的实际值可能会很大,但其实分别拆分读写锁的值不一定大,只是读锁值表示在高位,会造成state值很大。
3、一个线程获取到写锁,又获取到读锁情况(锁降级):
state = 65537,w=1, r=1
state二进制表示: 00000000 00000001 00000000 00000001
锁降级代码演示如下:
package readwritelock; import java.util.concurrent.locks.ReentrantReadWriteLock; /** * @author zdd * 2019/12/30 上午 * Description: 锁降级测试 */ public class ReadWriteLockTest { static Integer shareVar = 0; public static void main(String[] args) { ReentrantReadWriteLock rw = new ReentrantReadWriteLock(); //1,首先获取写锁 rw.writeLock().lock(); //2.修改共享变量值 shareVar = 10 ; //3.再获取读锁 rw.readLock().lock(); System.out.println("读取变量值 shareVar:"+ shareVar); //4.释放写锁 rw.writeLock().unlock(); //5.释放读锁 rw.readLock().unlock(); } } 2、类结构和构造方法ReentrantReadWriteLock 类中有ReadLock和WriteLock,分别对应读锁和写锁,而读写锁又分为公平方式和非公平方式获取锁。
简略类图结构如下:
构造方法如下:根据传入参数设置公平或者非公平获取锁方式,默认是非公平方式
public ReentrantReadWriteLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); } 3、写锁由于写锁是独占锁,由于写锁是独占锁,获取写锁的方式在AQS中已经说过了,详见AQS源代码分析, 只是每个子类的尝试获取锁方式不同,所以ReentrantReadWriteLock类获取写锁过程就看一下尝试获取锁方法的源码。
3.1、尝试获取锁tryAcquire(int acquires),获取锁失败则加入同步队列中等待获取锁,源代码如下:
protected final boolean tryAcquire(int acquires) { Thread current = Thread.currentThread(); //1,获取同步状态state的值,注意该值可表示读写锁的同步状态 int c = getState(); //2,获取写锁状态,低16位的值 int w = exclusiveCount(c); //3,如果同步锁状态不为0,有线程已经获取到了锁 if (c != 0) { //4,w==0则表示写锁为0,那么一定有线程获取了读锁,需要等待,读写互斥 //current != getExclusiveOwnerThread() 当前线程不等于已经获取到写锁的线程,则也需等待其释放,写写互斥 if (w == 0 || current != getExclusiveOwnerThread()) return false; //5,此时再次获取锁,判断锁重入次数是否超过最大限定次数 if (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error("Maximum lock count exceeded"); //更新写锁重入次数 setState(c + acquires); return true; } //6,代码执行这,一定是c==0,同步锁空闲情况 //writerShouldBlock该方法是基于公平锁和非公平锁2种方式的体现 if (writerShouldBlock() || !compareAndSetState(c, c + acquires)) return false; //获取到锁,设置独占锁为当前写锁线程 setExclusiveOwnerThread(current); return true; }写锁是否应该阻塞等待
1、 非公平锁方式
final boolean writerShouldBlock() { //直接返回false return false; // writers can always barge }2、公平锁方式