ReentrantReadWriteLock
ReentrantReadWriteLock 这个对象,有两个内部类,readLock和writeLock,都有一个aqs的属性sync,实例化的时候,获取的是从ReentrantReadWriteLock自己的重写的内部类sync继承了aqs
看readLock的lock()方法
RWlock 的 内部类sync 继承了aqs之后,对state进行了设计,后16位用来表示exlusiveCount,排他的数目。前16位用来表示sharedCount,共享的数目。readLock 的 Lock 调用的是 sync.acquireShared(1),这是aqs的方法,
if (tryAcquireShared(arg) < 0)
doAcquireShared(arg);
其中,tryAcquireShared是RWLock自己重写了的
用意是:试着获取共享锁,如果获取成功,返回的是正数,如果获取失败,返回的是-1,
逻辑是:
如果exlusiveCount不为0,说明此时有人使用排它锁,而且排它锁的线程不是当前线程,所以不能重入,那么现在的试图获取共享锁的操作是失败的
如果以上不成立,那么,说明可以获取共享锁,如果用cas添加sharedcount成功,那么返回1
否则,进入full啥啥啥方法,逻辑和本方法差不多,只不过在for循环中,为了弥补cas miss,其实是个延迟加载
看readLock的unlock()方法
public void unlock() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
其中,tryReleaseShared是RWLOCK重写的,tryReleaseShared的逻辑是,获取sharedstate,减一,返回剩下的sharedstate是否等于0,如果不为0,不执行doReleaseShared方法,否则执行
doReleaseShared是AQS的,逻辑是很熟悉的:将head节点的后继节点唤醒。现在是readlock获取到锁之后的unlock,那么挂起线程的列表中绝不会有readlock的申请者,因为是共享的,所以试图获取读锁的线程不会被挂起。所以挂起的线程都是
写锁,那么现在读锁全部释放,唤醒写锁线程也是非常合理的。
看WriteLock的lock()方法
public void lock() {
sync.acquire(1);
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
其实还是正常的获取锁的逻辑:尝试获取,如果获取到了,就设置state,exlusiveThread等待,然后往下走,如果获取不到就把线程挂起到队列里
关键是尝试获取的逻辑不同,交给不同的子类sync重写
RWLOCK的tryAcquire的逻辑是:
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);
if (c != 0) {
// (Note: if c != 0 and w == 0 then shared count != 0)
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
// Reentrant acquire
setState(c + acquires);
return true;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
先不看具体逻辑,试想一个,如果一个写锁可以获取,那么前提应该是,没有读锁,没有任何别的写锁,也就是如果有写锁,只能是自己,这也是c != 0中的第一个条件判断的,其他的判断都是判断有没有其他写锁了,这个和普通的独占锁是一样的。
看WriteLock的unlock()方法
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
还是一样的逻辑,try方法自己重写,其他方法继承,
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
逻辑也很简单,减去state上的数目,因为exlusive的是后16位,所以直接减就行了,然后看看后16位是不是0,如果是的话返回真,不是的返回假。返回真的话,就可以唤醒挂起的线程,这个时候的挂起线程就是等待的写线程。
ReentrantReadWriteLock的更多相关文章
- 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock
ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...
- 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock
ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...
- 【JUC】JDK1.8源码分析之ReentrantReadWriteLock(七)
一.前言 在分析了锁框架的其他类之后,下面进入锁框架中最后一个类ReentrantReadWriteLock的分析,它表示可重入读写锁,ReentrantReadWriteLock中包含了两种锁,读锁 ...
- Lock、ReentrantLock、synchronized、ReentrantReadWriteLock使用
先来看一段代码,实现如下打印效果: 1 2 A 3 4 B 5 6 C 7 8 D 9 10 E 11 12 F 13 14 G 15 16 H 17 18 I 19 20 J 21 22 K 23 ...
- Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock
概要 Java的JUC(java.util.concurrent)包中的锁包括"独占锁"和"共享锁".在“Java多线程系列--“JUC锁”02之 互斥锁Ree ...
- ReentrantReadWriteLock读写锁详解
一.读写锁简介 现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁.在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源:但是如果一个线 ...
- ReentrantReadWriteLock类和ReentrantLock类的区别
Java.util.concurrent.locks包定义了两个锁类,ReentrantLock和ReentrantReadWriteLock类. 当有很多线程都从某个数据结构中读取数据而很少有线程对 ...
- 多线程之ReentrantReadWriteLock
java5以后在java.util.concurrent包下,有很多的并发类,可以让我们摆脱java5时,笨重的写法来满足多线程,而且提供了更加丰富的使用场景能力 其中,在locks包下,提供了 Re ...
- Java中的显示锁 ReentrantLock 和 ReentrantReadWriteLock
在Java1.5中引入了两种显示锁,分别是可重入锁ReentrantLock和可重入读写锁ReentrantReadWriteLock.它们分别实现接口Lock和ReadWriteLock.(注意:s ...
- java ReentrantReadWriteLock
// read and write lock is mutual exclusion lock //Listing 7-3. Using ReadWriteLock to Satisfy a Dict ...
随机推荐
- LeetCode--007--整数反转(java)
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转. 示例 1: 输入: 123 输出: 321 示例 2: 输入: -123 输出: -321 示例 3: 输入: 120 输出 ...
- Linux中man手册的使用
Linux中man手册的使用 ——以CentOS6.8为例 本文旨在介绍在Linux中如何快速入手新命令,毕竟在Linux系统中,可以通过命令完成一切操作. 相关命令:help man whatis ...
- 廖雪峰网站:学习python基础知识—判断(三)
一.判断 1.条件判断 age = 18 if age >= 18: print('your are is', age) print('adult') age = 3 if age >= ...
- Git-解释“Swap file .MERGE_MSG.swp already exists”的问题
当合并代码时非正常保存退出遇到的问题. 博客原文: https://blog.csdn.net/qq_32452623/article/details/78395832
- MySQL 分支和循环结构
1.if else分支 mysql:用elseif Oracle:用elsif 可以用select直接查看获取的值或者一个变量. create procedure pd_t ...
- Spring Boot集成Thymeleaf
Thymeleaf是一个java类库,是一个xml/xhtml/html5的模板引擎,可以作为mvc的web应用的view层.Thymeleaf提供了额外的模块与Spring MVC集成,所以我们可以 ...
- UI基础三:简单的BOL报表开发
巧了...刚好一个需求,就直接来撸起来吧. 需要做一个报表: 1.创建查询结构和结果结构 2.创建实施类: SE24创建ZCL_JPEXPORT_ORDER_IL 更改父类:CL_WCF_GENIL_ ...
- 局域网两台机器ping超时
在防火墙的高级设置中的入站规则里,找icmpv4 ,我的两条电脑都是无线连的,看你的无线是专用还是公用,开启对应的规则. windows默认是关闭的,我的系统前些天刚重置过,ping超时,还是要手动开 ...
- BFPRT 算法 (TOP-K 问题)——本质就是在利用分组中位数的中位数来找到较快排更合适的pivot元素
先说快排最坏情况下的时间复杂度为n^2. 正常情况: 最坏的情况下,待排序的记录序列正序或逆序,每次划分只能得到一个比上一次划分少一个记录的子序列,(另一个子序列为空).此时,必须经过n-1次递归 ...
- jstack Dump 日志文件中的线程状态
[转]jstack Dump 日志文件中的线程状态 dump 文件里,值得关注的线程状态有: 死锁,Deadlock(重点关注) 执行中,Runnable 等待资源,Waiting on condi ...