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. android -------- 颜色的半透明效果配置

    最近有朋友问我 Android 背景颜色的半透明效果配置,我网上看资料,总结了一下, 开发中也是常常遇到的,所以来写篇博客 常用的颜色值格式有:  RGB    ARGB    RRGGBB   AA ...

  2. selenium 简单粗暴的定位方法

  3. 【PowerDesigner】【4】连接数据库并生成ER图

    文字版: 1,File→Reverse Engineer→Database...., 2,新窗口database reverse engineering打开后,填写名称(Model name),选择数 ...

  4. 使用maven构建一个web项目

                          使用maven构建一个web项目     首先建立一个maven项目(关于环境配置上节有详细过程): 1)-->右键new,-->project ...

  5. ActiveMQ 事务和XA

    1. 客户端怎样显式地使用事务? producer 开启事务(代码片段): ActiveMQSession session = (ActiveMQSession)connection.createSe ...

  6. provider和consumer配置参数的优先级

    <dubbo:service>和<dubbo:reference>存在一些相同的参数,例如:timeout,retries等,那么哪个配置的优先级高呢? consumer合并u ...

  7. 这些你都了解么------程序员"跳槽"法则

    篇头语: “跳槽”这个词是从我报了"软件工程"这个专业后就已经开始听说的词了, 在大学中老师上课也会常说:“等你们参加工作以后,工资低不怕,没事就跳槽,之后工资就高了”: 我相信听 ...

  8. Linux查看某个命令属于哪个包

    有时修我们需要某个命令但其没有安装,提供该命令的包名也与命令名相差很大直接查找命令名找不到包,如rexec. 此时我们就非常需要这样一个工具:可以根据最终的命令查找提供该命令的软件包. 类型 命令 说 ...

  9. input实时监听

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  10. 通过css 实现“瀑布流”

    .hot_list{-webkit-column-count: 2; -moz-column-count: 2; column-count: 2; -moz-column-gap:7px; -webk ...