ReentrantReadWriteLock源码分析
代码在后面
读锁 = 共享锁
读锁写锁,公用一个Sync AQS state。
写锁是排他的,看到有人获取锁,他不会去获取,他获取了锁,别人也不会进来获取锁。
写锁的获取跟ReentarntLock一样,每次加1,是一个独占锁,只要有人获取了锁,自己就去排队,排队时候节点是EXCLUSIVE的节点,入队方法acquireQueued和ReentarntLock一样,会设置OwnerThread。
读锁先获取锁,后面有读锁进来,多个读线程共存时候,第一个读线程设置firstReader,其余读线程设置threadLocals属性,然后获取锁,读锁每次增加65536,
写锁再进来,就去排队。
读锁再又进来,读锁还是去排队,
读锁不会设置OwnerThread,只是会state增加65536,写锁会忽略大于65536的部分。
state!=0,state去掉前16位=0,说明有读锁进去,写锁不进去。
State高位存储读锁获取次数,低位存储写锁获取次数。
设置threadLocals属性的读线程unlock时候清除threadLocalMap的标记,设置firstReader的读线程unlock时候设置firstReader=null,并且state减65536,
//读锁进来,首先判断state后16位,有写锁就去排队,没有写锁就设置firstReader或者firstReaderHoldCount++或者当前线程的threadLocals并且state增加65536
//写锁进来时候,首先判断state,有读锁写锁就去排队,
1.读锁进来,不看owenerThread,看的是state,去掉前面16位=0,说明没有写线程获取锁,就设置firstReader或者threadLocalMap,state增加65536。state去掉前面16位!=0说明有写线程获得了锁,就去排队。如果队列第一个是写线程,就去排队。 如果后面还有读线程进来,照样。
2.写锁进来,state!=0,state去掉前面16位=0,说明state已经加了几个65536了,说明有线程在读,写锁要去排队。state=0说明没有写线程获取锁,没有读线程在读,就去获取锁。state!=0,state去掉前面16位!=0,说明state有写线程获取锁,就去排队。
读锁每次加65536,不设置owenerThread。写锁每次加1,设置owenerThread。
读:去掉前面16!=0就去排队,队列空设置firstReader或者threadLocalMap,第一个节点是写线程排队,第一个节点是读线程设置firstReader或者threadLocalMap。
写:state!=0,去掉前面16位=0去排队,state=0获取锁。


if (exclusiveCount(c) != 0 /*去掉前面16位,*/ && getExclusiveOwnerThread() != current)
获取读锁时候,去掉前面16位!=0,OwnerThread() = current,说明里面有写锁了,并且是自己。说明一个线程先获取写锁在获取读锁,那么这个线程占据了owenerThread和firstReader或者threadLocalMap。
public class ReadWriteLockTest<E> {
private final Map<String, String> map = new TreeMap<>();
private final ReentrantReadWriteLock1 lock = new ReentrantReadWriteLock1();
//写的时候,不能读不能写。 读的时候,不能写可以读。
//读线程获取锁,其他读线程可以获取锁,写线程不能获取锁
//写线程获取锁,读线程写线程不能获取锁
private final ReentrantReadWriteLock1.ReadLock readLock = lock.readLock();
private final ReentrantReadWriteLock1.WriteLock writeLock = lock.writeLock();
public ReadWriteLockTest() {
}
public String write(String key, String value) throws InterruptedException {
writeLock.lock();//写锁是排他的,看到有人获取锁,他不会去获取,他获取了锁别人也不会进来获取锁。
readLock.lock();
// writeLock.lockInterruptibly();
// writeLock.tryLock();
try {
return map.put(key, value);
} finally {
writeLock.unlock();//写锁释放,就唤醒AQS
}
}
public String read(String key) throws InterruptedException {
readLock.lock();//获取的是共享锁
// writeLock.lock();
// readLock.lockInterruptibly();
// readLock.tryLock();
try {
return map.get(key);
} finally {
readLock.unlock();//读锁全部释放完了,才会去唤醒AQS
}
}
private static ReadWriteLockTest<Integer> tt = new ReadWriteLockTest<Integer>();
public static void main(String[] args) {
new Thread(() -> {
int i = ;
while (true) {
Write w = new Write("写--" + (i++));
w.start();
}
}).start();
new Thread(() -> {
int j = ;
while (true) {
Read s1 = new Read("读--" + (j++));
s1.start();
// Read s2 = new Read("读--" + (j++));
// s2.start();
// Read s3 = new Read("读--" + (j++));
// s3.start();
// s1.interrupt();
// s2.interrupt();
// s3.interrupt();
}
}).start();
}
static int i =;static int j = ;
static class Write extends Thread {
Write(String name) {
super(name);
}
@Override
public void run() {
try {
tt.write((i++)+"",(j++)+"");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class Read extends Thread {
Read(String name) {
super(name);
}
@Override
public void run() {
try {
tt.read((i--)+"");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
ReentrantReadWriteLock源码分析的更多相关文章
- 【Java并发编程】16、ReentrantReadWriteLock源码分析
一.前言 在分析了锁框架的其他类之后,下面进入锁框架中最后一个类ReentrantReadWriteLock的分析,它表示可重入读写锁,ReentrantReadWriteLock中包含了两种锁,读锁 ...
- ReentrantReadWriteLock 源码分析
ReentrantReadWriteLock 源码分析: 1:数据结构: 成员变量: private final ReentrantReadWriteLock.ReadLock readerLock ...
- Java并发指南10:Java 读写锁 ReentrantReadWriteLock 源码分析
Java 读写锁 ReentrantReadWriteLock 源码分析 转自:https://www.javadoop.com/post/reentrant-read-write-lock#toc5 ...
- ReentrantReadWriteLock源码分析(一)
此处源码分析,主要是基于读锁,非公平机制,JDK1.8. 问题: 1.ReentrantReadWriteLock是如何创建读锁与写锁? 2.读锁与写锁的区别是什么? 3.锁的重入次数与获取锁的线程数 ...
- Java显式锁学习总结之五:ReentrantReadWriteLock源码分析
概述 我们在介绍AbstractQueuedSynchronizer的时候介绍过,AQS支持独占式同步状态获取/释放.共享式同步状态获取/释放两种模式,对应的典型应用分别是ReentrantLock和 ...
- ReentrantReadWriteLock源码分析笔记
ReentrantReadWriteLock包含两把锁,一是读锁ReadLock, 此乃共享锁, 一是写锁WriteLock, 此乃排它锁. 这两把锁都是基于AQS来实现的. 下面通过源码来看看Ree ...
- ReentrantReadWriteLock 源码分析以及 AQS 共享锁 (二)
前言 上一篇讲解了 AQS 的独占锁部分(参看:ReentrantLock 源码分析以及 AQS (一)),这一篇将介绍 AQS 的共享锁,以及基于共享锁实现读写锁分离的 ReentrantReadW ...
- ReentrantReadWriteLock源码分析及理解
本文结构 读写锁简介:介绍读写锁.读写锁的特性以及类定义信息 公平策略及Sync同步器:介绍读写锁提供的公平策略以及同步器源码分析 读锁:介绍读锁的一些常用操作和读锁的加锁.解锁的源码分析 写锁:介绍 ...
- 多线程之美7一ReentrantReadWriteLock源码分析
目录 前言 在多线程环境下,为了保证线程安全, 我们通常会对共享资源加锁操作,我们常用Synchronized关键字或者ReentrantLock 来实现,这两者加锁方式都是排他锁,即同一时刻最多允许 ...
- Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析
我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 Reentrant ...
随机推荐
- javascript(五)表达式
表达式 (expression) JavaScript中的一个短语, JavaScript解释器会将其计算(evaluate) 出一 个结果.程序中的常量是最简单的一类表达式.变量名也是一种简单的表达 ...
- 【USACO】香甜的黄油
这是一道来自USACO的题,一般歪果仁的题都不是很好做,就比如这题 题目描述: 农夫John发现做出全威斯康辛州最甜的黄油的方法:糖.把糖放在一片牧场上,他知道N(1<=N<=500)只奶 ...
- Spring Boot 使用 JWT 进行身份和权限验证
上周写了一个 适合初学者入门 Spring Security With JWT 的 Demo,这篇文章主要是对代码中涉及到的比较重要的知识点的说明. 适合初学者入门 Spring Security W ...
- vue项目进入mui.js报错 typeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode .....
在做项目时,引用mui报错如下 看样子就是不支持严格模式吧. 解决方法是在根目录 下的.babelrc文件里面添加过滤掉.不用严格模式
- vue+element下拉框样式的点击按钮
项目中点击按钮实在太多了,怎么办呢?我们就可以将它们制作成像下拉框那样的类似操作 1.HTML样式部分:关键点在于command 方法和属性 1 <el-dropdown 2 size=&quo ...
- 【转载】Gradle学习 第十一章:使用Gradle命令行
转载地址:http://ask.android-studio.org/?/article/94 This chapter introduces the basics of the Gradle com ...
- 交叉编译用于生成aarch64指令的GCC (9.2)
参考 Building GCC as a cross compiler for Raspberry Pi How to Build a GCC Cross-Compiler 环境 PC: ubuntu ...
- 查看 Python 对象的属性
1 .dir函数可以返回一个对象的所有属性和方法. 示例:查看 int 对象的属性和方法 示例: 查看 dict 对象的属性和方法 标红的这些是不是遇到过? 2.help()调用内置帮助系统 示例 3 ...
- 最常见Linux操作
命令 含义 cd /home/hadoop #把/home/hadoop设置为当前目录 cd .. #返回上一级目录 cd ~ #进入到当前Linux系统登录用户的主目录(或主文件夹).在 Linux ...
- 借助模板类自动实现COM连接点接收器(Sink)
本文的更新:借助模板类自动实现COM连接点接收器(Sink)更新 (2014-06-09 17:09) 最初的代码源自free2000fly的一个标准的 COM 连接点接收器(Sink)的实现, 使用 ...