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的更多相关文章

  1. 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock

    ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...

  2. 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock

    ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...

  3. 【JUC】JDK1.8源码分析之ReentrantReadWriteLock(七)

    一.前言 在分析了锁框架的其他类之后,下面进入锁框架中最后一个类ReentrantReadWriteLock的分析,它表示可重入读写锁,ReentrantReadWriteLock中包含了两种锁,读锁 ...

  4. 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 ...

  5. Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock

    概要 Java的JUC(java.util.concurrent)包中的锁包括"独占锁"和"共享锁".在“Java多线程系列--“JUC锁”02之 互斥锁Ree ...

  6. ReentrantReadWriteLock读写锁详解

    一.读写锁简介 现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁.在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源:但是如果一个线 ...

  7. ReentrantReadWriteLock类和ReentrantLock类的区别

    Java.util.concurrent.locks包定义了两个锁类,ReentrantLock和ReentrantReadWriteLock类. 当有很多线程都从某个数据结构中读取数据而很少有线程对 ...

  8. 多线程之ReentrantReadWriteLock

    java5以后在java.util.concurrent包下,有很多的并发类,可以让我们摆脱java5时,笨重的写法来满足多线程,而且提供了更加丰富的使用场景能力 其中,在locks包下,提供了 Re ...

  9. Java中的显示锁 ReentrantLock 和 ReentrantReadWriteLock

    在Java1.5中引入了两种显示锁,分别是可重入锁ReentrantLock和可重入读写锁ReentrantReadWriteLock.它们分别实现接口Lock和ReadWriteLock.(注意:s ...

  10. java ReentrantReadWriteLock

    // read and write lock is mutual exclusion lock //Listing 7-3. Using ReadWriteLock to Satisfy a Dict ...

随机推荐

  1. 【WPF】 Behavior

    Hello,Behavior   引言         在看PDC-09大会的视频时,其中一篇讲利用Blend来扩展Silverlight元素的行 为,当时感觉很酷:在Blend中,将MouseDra ...

  2. Creating a Hadoop-2.x project in Eclipse

    Creating a Hadoop-2.x project in Eclipse hortonworks:MapReduce Ports http://docs.hortonworks.com/HDP ...

  3. Django用户认证组件

    用户认证 主要分两部分: 1.auth模块   from django.contrib import auth 2.User对象 from django.contrib.auth.models imp ...

  4. vue, vux调用微信点击图片,上传图片,删除图片,接口,其中选图接口,苹果手机显示有问题,查看不到图片,提交会提示fail not exist,解决如下

    <template> <div v-cloak v-show="show"> <div v-show="mailbox"> ...

  5. loj#6062. 「2017 山东一轮集训 Day2」Pair hall定理+线段树

    题意:给出一个长度为 n的数列 a和一个长度为 m 的数列 b,求 a有多少个长度为 m的连续子数列能与 b匹配.两个数列可以匹配,当且仅当存在一种方案,使两个数列中的数可以两两配对,两个数可以配对当 ...

  6. yum源仓库搭建

    系统:centos7 一.安装nginx yum install -y nginx yum  install -y createrepo   安装建yum源仓库的工具,可以用来建立yum仓库yum  ...

  7. SpringBoot项目Shiro的实现(二)

    在看此小节前,您可能需要先看:http://www.cnblogs.com/conswin/p/7478557.html 紧接上一篇,在上一篇我们简单实现了一个Springboot的小程序,但我们发现 ...

  8. windows 系统分布式版本控制 git 使用学习

    1. 在 Windows 上安装 Git 在Windows上使用Git,可以从Git官网直接下载安装程序,(网速慢的同学请移步国内镜像),然后按默认选项安装即可. 安装完成后,在开始菜单里找到“Git ...

  9. 小程序-wepy学习

    组件通信与交互 推荐网址:https://tencent.github.io/wepy/document.html#/?id=%e7%bb%84%e4%bb%b6%e9%80%9a%e4%bf%a1% ...

  10. servlet/和/*匹配的区别

    两者真正的区别是,两者的长度不同,根据最长路径匹配的优先级,/*比/更容易被选中,而/的真正含义是,缺省匹配.既所有的URL都无法被选中的时候,就一定会选中/,可见它的优先级是最低的,这就两者的区别.