文档章节

ReentrantReadWriteLock

o
 ovirtKg
发布于 2017/03/21 10:06
字数 864
阅读 11
收藏 0

读写锁是应对多线程环境下,读多写少。可以并发读,读与写之间的互斥。接下来先来看下其类的结构图,如下

 

 

从图中可以看出,读写分别对应一个lock,而与其它 并发类一样,内部实现依然是通过继承AQS的 sync来实现,并且同样提供了两个实现,Fair与NonFair。默认是非公平。

AQS中有一个state字段(int类型,32位)用来描述有多少线程获持有锁。在独占锁的时代这个值通常是0或者1(如果是重入的就是重入的次数),读写锁中需要两个数来描述读锁(共享锁)和写锁(独占锁)的数量。于是在ReentrantReadWrilteLock里面将state这个字段一分为二,高位16位表示共享锁的数量,低位16位表示独占锁的数量(或者重入数量)。2^16-1=65536,这就是上节中提到的为什么共享锁和独占锁的数量最大只能是65535的原因了。

如readLock的lock就是 通过sync的acquiredShared(1),来获取资源。实现如下

//AQS 
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
            doAcquireShared(arg);
}

而不同并发工具通过实现 tryAcquiredShared  的方法,来判断在什么条件下能够获取共享资源,同样非共享的机制类似,不过方法名就没有shared,如果tryAcquiredShared   返回值 小于0,那么将会执行AQS的doAcquredShared的阻塞方法中,内部通过一个双向的链表来实现。

在读写锁的读锁中,尝试获取锁资源的源码 :

        protected final int tryAcquireShared(int unused) {
            /*
             * Walkthrough:
             * 1. If write lock held by another thread, fail.
             * 2. Otherwise, this thread is eligible for
             *    lock wrt state, so ask if it should block
             *    because of queue policy. If not, try
             *    to grant by CASing state and updating count.
             *    Note that step does not check for reentrant
             *    acquires, which is postponed to full version
             *    to avoid having to check hold count in
             *    the more typical non-reentrant case.
             * 3. If step 2 fails either because thread
             *    apparently not eligible or CAS fails or count
             *    saturated, chain to version with full retry loop.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            if (exclusiveCount(c) != 0 && //有写锁且非当前,失败
                getExclusiveOwnerThread() != current)
                return -1;
            int r = sharedCount(c);// 检测当前获取读锁的个数,高16位表示 读锁,右移16位
            if (!readerShouldBlock() &&  //对于不公平,队列首部的node是否是共享的,而公平的则队列不为空
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                if (r == 0) {
                    firstReader = current;
                    firstReaderHoldCount = 1;
                } else if (firstReader == current) {
                    firstReaderHoldCount++;
                } else {
                    HoldCounter rh = cachedHoldCounter;
                    if (rh == null || rh.tid != getThreadId(current))
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;
                }
                return 1;
            }
            return fullTryAcquireShared(current);
        }

该方法在首先以及在加入CLH队列后 在一定条件(前node是head,保证了公平性,需按顺序唤醒,且被唤醒)下会在次调用该方法获取锁的资源。

读锁的lock 与tryLock有一点区别是

而lock是读锁时,当有写锁在CLH队列时,此时获取读锁应等到写锁释放后才能获取,而tryLock是在没有写入锁或者写入锁是当前线程,并且读线程共享锁数量没有超过65535个时就能获取。意味着只要不是写锁,读锁下不管是否有写锁在等待都能获取。

写入锁的tryLock 条件是  没有写入锁或者写入锁是当前线程,并且尝试一次修改state成功。失败直接返回,不阻塞。 而lock获取失败时是阻塞的。

 

 

 

http://blog.csdn.net/u012881904/article/details/51051138

http://blog.csdn.net/vernonzheng/article/details/8297230

 

© 著作权归作者所有

上一篇: copyOnWrite
下一篇: java G1
o
粉丝 3
博文 57
码字总数 48798
作品 0
景德镇
私信 提问
ReentrantReadWriteLock与AtomicInteger的简单应用与对比

背景说明:   模拟春节抢票场景,500个线程(50并发)抢100张票,余票足够则成功取得票,否则不成功。 ReentrantReadWriteLock实现版: public class ReadWriteLockTest { private static fi...

zhengweihao
2015/12/08
126
0
ReentrantReadWriteLock读写锁及其在 RxCache 中的使用

一. ReentrantReadWriteLock读写锁 Lock 是相当于 synchronized 更面向对象的同步方式,ReentrantLock 是 Lock 的实现。 本文要介绍的 ReentrantReadWriteLock 跟 ReentrantLock 并没有直接的...

fengzhizi715
01/21
0
0
读写锁ReentrantReadWriteLock

锁是java并发同步的重要利器,比如volatile和synchronized等。这些都是排他性的,同一时刻允许一个线程跑。 但是有时候我们希望读多线程跑无阻塞,读写锁分开这样就能提高效率!很新运concurr...

is晓歌
2017/10/31
0
0
关于concurrent包 线程池、资源封锁和队列、ReentrantReadWriteLock介绍

jdk1.5后,提供了java.util.concurrent包,它可以实现线程池,你把线程当成普通对象就可以了,它来负责调度和执行 包括两类线程池 固定线程池 可变线程池 延迟线程池 固定线程池 public sta...

JavaGG
2009/06/11
1K
1
concurrent包 线程池、资源封锁和队列、ReentrantReadWriteLock介绍

jdk1.5后,提供了java.util.concurrent包,它可以实现线程池,你把线程当成普通对象就可以了,它来负责调度和执行 包括两类线程池 固定线程池 可变线程池 延迟线程池 固定线程池 public sta...

JavaGG
2010/03/24
982
0

没有更多内容

加载失败,请刷新页面

加载更多

Mybatis Plus删除

/** @author beth @data 2019-10-17 00:30 */ @RunWith(SpringRunner.class) @SpringBootTest public class DeleteTest { @Autowired private UserInfoMapper userInfoMapper; /** 根据id删除......

一个yuanbeth
今天
4
0
总结

一、设计模式 简单工厂:一个简单而且比较杂的工厂,可以创建任何对象给你 复杂工厂:先创建一种基础类型的工厂接口,然后各自集成实现这个接口,但是每个工厂都是这个基础类的扩展分类,spr...

BobwithB
今天
4
0
java内存模型

前言 Java作为一种面向对象的,跨平台语言,其对象、内存等一直是比较难的知识点。而且很多概念的名称看起来又那么相似,很多人会傻傻分不清楚。比如本文我们要讨论的JVM内存结构、Java内存模...

ls_cherish
今天
4
0
友元函数强制转换

友元函数强制转换 p522

天王盖地虎626
昨天
5
0
js中实现页面跳转(返回前一页、后一页)

本文转载于:专业的前端网站➸js中实现页面跳转(返回前一页、后一页) 一:JS 重载页面,本地刷新,返回上一页 复制代码代码如下: <a href="javascript:history.go(-1)">返回上一页</a> <a h...

前端老手
昨天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部