ReentrantReadWriteLock源码
@SuppressWarnings("restriction")
public class ReentrantReadWriteLock1 implements ReadWriteLock, java.io.Serializable {
private static final long serialVersionUID = -6992448646407690164L;
private final ReentrantReadWriteLock1.ReadLock readerLock;
private final ReentrantReadWriteLock1.WriteLock writerLock;
final Sync sync;
public ReentrantReadWriteLock1() {
this(false);
}
public ReentrantReadWriteLock1(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);//写锁和读锁,公用同一个Sync,也就是同一个AQS队列,
writerLock = new WriteLock(this);
}
public ReentrantReadWriteLock1.WriteLock writeLock() {
return writerLock;
}
public ReentrantReadWriteLock1.ReadLock readLock() {
return readerLock;
}
abstract static class Sync extends AbstractQueuedSynchronizer1 {//ReentrantLock有自己的Sync,都继承AQS类,
private static final long serialVersionUID = 6317671515068378041L;
static final int SHARED_SHIFT = ;
static final int SHARED_UNIT = ( << SHARED_SHIFT);// 2^16
static final int MAX_COUNT = ( << SHARED_SHIFT) - ;// 2^16-1
static final int EXCLUSIVE_MASK = ( << SHARED_SHIFT) - ;// 2^16-1
static int sharedCount(int c) {//小于2^16=0,等于2^16=1,大于2^16>1,共享锁最大共享线程数=2^16-1,
return c >>> SHARED_SHIFT;// 右移16位,
}
static int exclusiveCount(int c) {
return c & EXCLUSIVE_MASK;// 去掉前面16位,
}
static final class HoldCounter {
int count = ;
final long tid = getThreadId(Thread.currentThread());
}
static final class ThreadLocalHoldCounter extends ThreadLocal<HoldCounter> {
public HoldCounter initialValue() {
return new HoldCounter();//ThreadLocalHoldCounter作为key,new HoldCounter()作为value,
}
}
//当前线程持有的可重入读锁的数量。构造函数中初始化。每当线程的读计数下降到0时删除。
private transient ThreadLocalHoldCounter readHolds;//只有一个
private transient HoldCounter cachedHoldCounter;//多个
private transient Thread firstReader = null;
private transient int firstReaderHoldCount;
Sync() {
readHolds = new ThreadLocalHoldCounter();//只有一个
setState(getState());
}
abstract boolean readerShouldBlock();
abstract boolean writerShouldBlock();
protected final boolean tryRelease(int releases) {//写锁释放
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;// 状态变量的值减1
boolean free = exclusiveCount(nextc) == ;//写锁=0
if (free)//getState()-releases == 0
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
protected final boolean tryAcquire(int acquires) {//WriteLock获取锁,多线程访问
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);//w=0则C=2^16,w!=0则C<2^16,写锁被获取的次数
if (c != ) {//锁里面有线程了重入锁,写锁只要看见state里面有线程就去排队(可能里面有读锁或者写锁),
// c!=0,w=0:说明C=2^16的整数倍,说明有读线程获取了锁,
if (w == || current != getExclusiveOwnerThread()) // c!=0,w=0,说明有读锁进去,写锁不进去,其它线程获取了互斥锁(写锁)
return false;//获取锁失败去排队
/*单线程进来,线程安全的。 */
//w!=0&¤t=OwnerThread,MAX_COUNT=2^16-1,就去加值,
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//w!=0&¤t=OwnerThread,MAX_COUNT=2^16-1,就去加值,
setState(c + acquires);//acquires每次都是从1开始的,C从0开始,所以c,w,acquires不可能大于2^16。
return true;
}
//c=0,锁里面没有线程,就要去抢锁。
//writerShouldBlock:非公平返回false,就去获取锁。
//writerShouldBlock:公平,返回true排队,返回false,就去获取锁。
//获取state成功设置owenerThread=自己,不去排队,获取state失败,去排队。
if (writerShouldBlock() || !compareAndSetState(c, c + acquires))
return false;
/*单线程进来,线程安全的。
compareAndSetState(c, c+acquires)可以作为一把锁,synchronized,
别的线程要想进到compareAndSetState包裹的代码里面去,必须重新获取新的c=c+acquires,但是进去if(c!=0)里面去了。
*/
setExclusiveOwnerThread(current);//获得锁。
return true;
}
protected final boolean tryReleaseShared(int unused) {// 读锁释放(共享锁),unused没有使用
Thread current = Thread.currentThread();
if (firstReader == current) {
// 如果第一个读者(读线程)是当前线程
// 就把它重入的次数减1
// 如果减到0了就把第一个读者置为空
if (firstReaderHoldCount == )
firstReader = null;
else
firstReaderHoldCount--;
} else {
// 如果第一个读者不是当前线程,一样地,把它重入的次数减1
HoldCounter rh = cachedHoldCounter;//最后获取读锁的HoldCounter
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();//get方法没有时候,就回去创建,有就返回。返回当前线程threadLcoalMap里面的那行记录
int count = rh.count;
if (count <= ) {
readHolds.remove();
if (count <= )
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {// 共享锁获取的次数减1,如果减为0了说明完全释放了,才返回true
int c = getState();
int nextc = c - SHARED_UNIT;//减去65536
if (compareAndSetState(c, nextc))
return nextc == ;//读锁完全释放了,
}
}
private IllegalMonitorStateException unmatchedUnlockException() {
return new IllegalMonitorStateException("attempt to unlock read lock, not locked by current thread");
}
//读锁每次进来加65536,写锁每次进来加1,
protected final int tryAcquireShared(int unused) {//ReadLock获取锁,走这个方法,并发问题,unused没有使用
// 在读写锁模式下,高16位存储的是共享锁(读锁)被获取的次数,低16位存储的是互斥锁(写锁)被获取的次数
Thread current = Thread.currentThread();
int c = getState();//state在AQS类里面,读锁写锁,公用一个Sync AQS state,写锁只能一个进去,另一个写锁进不去,读锁也进不去,
if (exclusiveCount(c) != /*去掉前面16位,*/ && getExclusiveOwnerThread() != current)//state!=0,并且 当前线程没有获取锁。如果写线程获取了锁,state+1就返回-1去排队。
return -;
int r = sharedCount(c);//右移16位, 读锁被获取的次数
//多线程可以进来
if (!readerShouldBlock()/* AQS队列第一个节点写线程跳过,没有第一个节点或者第一个是读线程就进去 */ && r < MAX_COUNT
&& compareAndSetState(c, c + SHARED_UNIT)/* c每次增加65536 */) {
//可以多线程进来,AQS队列没有节点 并且 c是2^16的整数倍=0就是没有写锁,第一个线程进来后只要后面的线程重新获取c就可以进来,
// 注意下面对firstReader的处理:firstReader是不会放到readHolds里的
// 这样,在读锁只有一个的情况下,就避免了查找readHolds。
if (r == ) {//r=0,c<2^16,没有读锁
firstReader = current;//获取读锁的线程,Thread
firstReaderHoldCount = ;
} else if (firstReader == current) {//重入锁
firstReaderHoldCount++;
} else {
//先查缓存
HoldCounter rh = cachedHoldCounter;//HoldCounter,缓存前一个线程的HoldCounter(线程id和获取锁次数)
if (rh == null || rh.tid != getThreadId(current))
//ThreadLocal里面get,ThreadLocalHoldCounter。
//当前线程的threadLocals属性的threadLocalMap里面加了一行记录(key=readHolds[ThreadLocalHoldCounter],value=cachedHoldCounter[HoldCounter]),
//其他线程也会在他的threadLocals的threadLocalMap里面加一行记录(key=readHolds[ThreadLocalHoldCounter],value=cachedHoldCounter[HoldCounter]),
//每个线程里面只有一行记录,ThreadLocal是公用的,因为只有一个ThreadLocal,value放的是线程的id和计数器。就这样线程就获取了锁,
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == )//当前线程就是上一次线程,就修改thradLocals
readHolds.set(rh);
rh.count++;//多个读,只有一个firstReader,其余的都是在线程里面的threadLocals里面加了一行记录,重入的次数加1(初始次数为0)
}
return ;//获取了锁
}
//有人在排队
return fullTryAcquireShared(current);
}
//在tryAcquireShared中经行了一次快速锁获取,但是由于CAS只能允许一个线程获取锁成功,且读锁是共享的,
//可能存在其他仍然可以获取锁的线程,所以在函数末尾调用函数fullTryAcquireShared来进行死循环的获取锁,
final int fullTryAcquireShared(Thread current) {//获取读锁
HoldCounter rh = null;
for (;;) {//死循环
int c = getState();
if (exclusiveCount(c) != ) {//去掉前面16位!= 0
if (getExclusiveOwnerThread() != current)//相等,就是先获取写锁在获取读锁,
return -;//排队
// 否则,我们持有独占锁;在这里阻塞将导致死锁。
} else if (readerShouldBlock()) {//去掉前面16位= 0,并且AQS队列有第一个节点是写锁不是读锁,
// 确保我们没有重新获取读锁
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
} else {
if (rh == null) {
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current)) {
rh = readHolds.get();//设置当前线程的threadLocals,key还是readHolds同一个ThreadLocal,
if (rh.count == )//!=0,就说明这个线程之前已经获取一次锁成功了,
readHolds.remove();//从当前线程threadLocals中移除这行记录,
}
}
if (rh.count == )
return -;//排队,
}
}
//AQS没有节点,有第一个节点,第一个节点只能是读节点,就去设置threadLcoalMap并且获取锁,
if (sharedCount(c) == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (sharedCount(c) == ) {//=0,就说明没有读线程,
firstReader = current;
firstReaderHoldCount = ;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
if (rh == null)
rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
else if (rh.count == )
readHolds.set(rh);
rh.count++;
cachedHoldCounter = rh; // cache for release
}
return ;//获取了锁
}
}
}
final boolean tryWriteLock() {
Thread current = Thread.currentThread();
int c = getState();
if (c != ) {
int w = exclusiveCount(c);
if (w == || current != getExclusiveOwnerThread())
return false;
if (w == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
}
//c=0
if (!compareAndSetState(c, c + ))
return false;
setExclusiveOwnerThread(current);
return true;
}
final boolean tryReadLock() {
Thread current = Thread.currentThread();
for (;;) {
int c = getState();
if (exclusiveCount(c) != && getExclusiveOwnerThread() != current)
return false;
int r = sharedCount(c);
if (r == MAX_COUNT)
throw new Error("Maximum lock count exceeded");
if (compareAndSetState(c, c + SHARED_UNIT)) {
if (r == ) {
firstReader = current;
firstReaderHoldCount = ;
} else if (firstReader == current) {
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == )
readHolds.set(rh);
rh.count++;
}
return true;
}
}
}
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
final Thread getOwner() {
return ((exclusiveCount(getState()) == ) ? null : getExclusiveOwnerThread());
}
final int getReadLockCount() {
return sharedCount(getState());
}
final boolean isWriteLocked() {
return exclusiveCount(getState()) != ;
}
final int getWriteHoldCount() {
return isHeldExclusively() ? exclusiveCount(getState()) : ;
}
final int getReadHoldCount() {
if (getReadLockCount() == )
return ;
Thread current = Thread.currentThread();
if (firstReader == current)
return firstReaderHoldCount;
HoldCounter rh = cachedHoldCounter;
if (rh != null && rh.tid == getThreadId(current))
return rh.count;
int count = readHolds.get().count;
if (count == )
readHolds.remove();
return count;
}
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
readHolds = new ThreadLocalHoldCounter();
setState(); // reset to unlocked state
}
final int getCount() {
return getState();
}
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = -8159625535654395037L;
final boolean writerShouldBlock() {//false获取锁。
return false;
}
final boolean readerShouldBlock() {// 非公平读是否要阻塞,true排队,false获取锁。
return apparentlyFirstQueuedIsExclusive();//AQS队列有第一个节点是写锁不是读锁,
}
}
static final class FairSync extends Sync {
private static final long serialVersionUID = -2274990926593161451L;
final boolean writerShouldBlock() {// 公平写是否要阻塞,true排队,false获取锁。
return hasQueuedPredecessors();
}
final boolean readerShouldBlock() {// 公平读是否要阻塞,true排队,false获取锁。
return hasQueuedPredecessors();
}
}
public static class ReadLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -5992448646407690164L;
private final Sync sync;
protected ReadLock(ReentrantReadWriteLock1 lock) {// 外部类this
sync = lock.sync;
}
public void lock() {//获取读锁,获取的是共享锁,调用sync.acquireShared(AQS的方法),写锁调用sync.acquire(AQS的方法)
try {
sync.acquireShared();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireSharedInterruptibly();
}
public boolean tryLock() {
return sync.tryReadLock();
}
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireSharedNanos(, unit.toNanos(timeout));
}
public void unlock() {
sync.releaseShared();
}
public Condition newCondition() {
throw new UnsupportedOperationException();
}
public String toString() {
int r = sync.getReadLockCount();
return super.toString() + "[Read locks = " + r + "]";
}
}
public static class WriteLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = -4992448646407690164L;
private final Sync sync;
protected WriteLock(ReentrantReadWriteLock1 lock) {
sync = lock.sync;
}
public void lock() {//获取写锁,写锁的获取逻辑和ReentrantLock一样,失败的加入AQS队列,
try {//读锁调用sync.acquireShared(AQS的方法),写锁调用sync.acquire(AQS的方法)
sync.acquire();//尝试获取锁,获取失败就在AQS阻塞排队
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly();
}
public boolean tryLock() {
return sync.tryWriteLock();//获取读锁,不在AQS类里面,在本Sync类里面,
}
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(, unit.toNanos(timeout));
}
public void unlock() {
sync.release();//写锁释放,线程安全,唤醒AQS头结点,
}
public Condition newCondition() {
return sync.newCondition();
}
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ? "[Unlocked]" : "[Locked by thread " + o.getName() + "]");
}
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
public int getHoldCount() {
return sync.getWriteHoldCount();
}
}
public final boolean isFair() {
return sync instanceof FairSync;
}
protected Thread getOwner() {
return sync.getOwner();
}
public int getReadLockCount() {
return sync.getReadLockCount();
}
public boolean isWriteLocked() {
return sync.isWriteLocked();
}
public boolean isWriteLockedByCurrentThread() {
return sync.isHeldExclusively();
}
public int getWriteHoldCount() {
return sync.getWriteHoldCount();
}
public int getReadHoldCount() {
return sync.getReadHoldCount();
}
protected Collection<Thread> getQueuedWriterThreads() {
return sync.getExclusiveQueuedThreads();
}
protected Collection<Thread> getQueuedReaderThreads() {
return sync.getSharedQueuedThreads();
}
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
public final int getQueueLength() {
return sync.getQueueLength();
}
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer1.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer1.ConditionObject) condition);
}
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer1.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer1.ConditionObject) condition);
}
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer1.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer1.ConditionObject) condition);
}
public String toString() {
int c = sync.getCount();
int w = Sync.exclusiveCount(c);
int r = Sync.sharedCount(c);
return super.toString() + "[Write locks = " + w + ", Read locks = " + r + "]";
}
// Thread Id可以被重写
static final long getThreadId(Thread thread) {
return UNSAFE.getLongVolatile(thread, TID_OFFSET);
}
private static final sun.misc.Unsafe UNSAFE;
private static final long TID_OFFSET;
static {
try {
UNSAFE = java.security.AccessController
.doPrivileged(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
public sun.misc.Unsafe run() throws Exception {
Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
for (java.lang.reflect.Field f : k.getDeclaredFields()) {
f.setAccessible(true);
Object x = f.get(null);
if (k.isInstance(x))
return k.cast(x);
}
throw new NoSuchFieldError("the Unsafe");
}
});
Class<?> tk = Thread.class;
TID_OFFSET = UNSAFE.objectFieldOffset(tk.getDeclaredField("tid"));
} catch (Exception e) {
throw new Error(e);
}
}
}
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源码解析
读写锁实现逻辑相对比较复杂,但是却是一个经常使用到的功能,希望将我对ReentrantReadWriteLock的源码的理解记录下来,可以对大家有帮助 前提条件 在理解ReentrantReadWri ...
- Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析
我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 Reentrant ...
- ReentrantReadWriteLock源码分析(一)
此处源码分析,主要是基于读锁,非公平机制,JDK1.8. 问题: 1.ReentrantReadWriteLock是如何创建读锁与写锁? 2.读锁与写锁的区别是什么? 3.锁的重入次数与获取锁的线程数 ...
- Java显式锁学习总结之五:ReentrantReadWriteLock源码分析
概述 我们在介绍AbstractQueuedSynchronizer的时候介绍过,AQS支持独占式同步状态获取/释放.共享式同步状态获取/释放两种模式,对应的典型应用分别是ReentrantLock和 ...
- Java多线程——ReentrantReadWriteLock源码阅读
之前讲了<AQS源码阅读>和<ReentrantLock源码阅读>,本次将延续阅读下ReentrantReadWriteLock,建议没看过之前两篇文章的,先大概了解下,有些内 ...
- 死磕 java同步系列之ReentrantReadWriteLock源码解析
问题 (1)读写锁是什么? (2)读写锁具有哪些特性? (3)ReentrantReadWriteLock是怎么实现读写锁的? (4)如何使用ReentrantReadWriteLock实现高效安全的 ...
- ReentrantReadWriteLock源码分析笔记
ReentrantReadWriteLock包含两把锁,一是读锁ReadLock, 此乃共享锁, 一是写锁WriteLock, 此乃排它锁. 这两把锁都是基于AQS来实现的. 下面通过源码来看看Ree ...
随机推荐
- input file 保存图片
Request.File["控件名称"].FileName 文件名称(没有路径) Request.File["控件名称"].SaveAs("路径名称& ...
- rabbitMQ基础应用
1.安装erlang [root@localhost ~]#yum -y install erlang 2.安装rabbitMQ [root@localhost ~]#yum -y install r ...
- 开发工具--浅谈Git
工具|浅谈Git Git这个工具,是我一直想写文章,终于我实现了我的想法.在我开始写之前,发表一下自己的看法,git只是一个工具,既然已经认定是一个工具,那么一定具备工具这类的共同特征,请用面向对象的 ...
- MySQL查询优化一例——也说说 Using intersect
生产上面有一条sql查询很慢,需要7到8秒左右,简化之后的sql如下所示: SELECT mingxi.* FROM ( SELECT btjc01.id, department.`name` AS ...
- ubuntu18 安装坑点记录(华硕飞行堡垒)
环境 电脑:华硕飞行堡垒FX53VD 显卡:集成显卡+NVIDIA显卡(linux版本很不友好) 镜像:ubuntu18.04.3 LTS 准备安装 * 制作启动盘(百度) * 设置U盘启动项:按F2 ...
- 设置linux代理完成apt-get
最近ubuntu的服务器被公司关闭了外网使用权限,但是安装软件又需要连接外网,那么就只能通过代理来连接了. 先按照下面的这篇帖子来设置windows端的代理. https://blog.csdn.ne ...
- https工具类
import org.apache.commons.lang.StringUtils; import javax.net.ssl.*; import java.io.*; import java.ne ...
- shell 脚本命令之alias
1.alias的功能 设置一个别名,即为一个长命令起一个新的名字 2.alias的基本格式 alias alias_name='origin_command' alias是指定别名命令的关键字 a ...
- Linux 安装Docker compose 快速方法
https://blog.csdn.net/ysk_xh_521/article/details/80443509 安装pipyum -y install epel-releaseyum -y ins ...
- unzip命令(转)
unzip命令用于解压缩由zip命令压缩的“.zip”压缩包. 语法 unzip(选项)(参数) 选项 -c:将解压缩的结果显示到屏幕上,并对字符做适当的转换: -f:更新现有的文件: -l:显示压缩 ...