`
Jen
  • 浏览: 57434 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

JUC代码浅析[3]——基于AQS的锁ReentrantReadWriteLock

    博客分类:
  • java
阅读更多

JUC 代码浅析 [3] ——基于 AQS 的锁 ReentrantReadWriteLock

       ReentrantReadWriteLock 也是基于 AQS 实现的锁,它的特点是一个资源能够被多个读线程访问,或者被一个写线程访问,读和写是互斥的,可以同时有多个读但只能有一个写,大量读操作的场景下性能较好。 ReentrantReadWriteLock 并没有实现 Lock 接口,而是内部实现了 ReadLock WriteLock 分别针对读和写操作。看起来像两个锁,但其实这两个锁只是进行了一层适配,它们的主体都是 Sync ReadLock WriteLock 分别使用 Sync 的共享和独占模式。

 

ReadLock 加锁和释放,就是向 sync 请求共享模式进入和释放

        public void lock () {

            sync.acquireShared(1);

        }

        public   void unlock () {

            sync.releaseShared(1);

        }

 

WriteLock 加锁和释放,就是向 sync 请求互斥模式进入和释放

public void lock() {

            sync.acquire (1);

        }

public void unlock () {

            sync.release(1);

        }

 

       sync 的实现有公平和非公平两种 ( 下面介绍区别 ) sync 使用 int 的低 16 位表示写计数,高 16 位表示读计数,所以读锁和写锁的最高重入次数为 65535 ,超出将抛出 Error

获取写锁的实现片段,逻辑是:

l  如果读计数不为 0 ,失败;

l  如果写计数不为 0 并且不是当前线程持有锁,失败

l  如果写计数超出 65535 ,失败,抛出 Error

l  如果写计数为 0 并且当前线程需要阻塞,或者 state 被其他线程改变了,失败

l  以上条件都不满足则当前线程拥有写锁

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" );

            }

            if ((w == 0 && writerShouldBlock(current)) ||

                !compareAndSetState(c, c + acquires))

                return false ;

            setExclusiveOwnerThread(current);

            return true ;

        }

 

       非公平 sync 的写线程在总是不需要阻塞

        final boolean writerShouldBlock (Thread current) {

            return false ; // writers can always barge

        }

 

       公平 sync 的写线程只要 AQS 队列不为空并且不在第一个位置的就需要阻塞

        final boolean writerShouldBlock(Thread current) {

            // only proceed if queue is empty or current thread at head

            return !isFirst(current);

        }

 

 

       写锁的释放,减去并检查 state 计数,为 0 则表示写锁已经可以释放了,不为 0 说明该线程重入了写锁并把剩余的计数写入 state

        protected final boolean tryRelease ( int releases) {

            int nextc = getState() - releases;

            if (Thread.currentThread() != getExclusiveOwnerThread())

                throw new IllegalMonitorStateException();

            if (exclusiveCount(nextc) == 0) {

                setExclusiveOwnerThread( null );

                setState(nextc);

                return true ;

            } else {

                setState(nextc);

                return false ;

            }

        }

 

读锁的获取,

1 如果已经有线程获得写锁,并且不是当前线程获得的,失败

2 如果重入的读计数超出 65535 ,失败,抛出 Error

3 否则如果线程不用阻塞,并且增加读计数成功,则成功获得读锁

4 如果第三步失败(可能由于线程需要阻塞或者 CAS 修改失败),   不断尝试去修改状态直到成功或者锁被写入线程占有(看 fullTryAcquireShared 的实现 )

        protected final int tryAcquireShared ( int unused) {

            Thread current = Thread.currentThread();

            int c = getState();

            if (exclusiveCount(c) != 0 &&

                getExclusiveOwnerThread() != current)

                return -1;

            if (sharedCount(c) == MAX_COUNT)

                throw new Error( "Maximum lock count exceeded" );

            if (!readerShouldBlock(current) &&

                compareAndSetState(c, c + SHARED_UNIT)) {

                HoldCounter rh = cachedHoldCounter;

                 if (rh == null || rh.tid != current.getId())

                    cachedHoldCounter = rh = readHolds.get();

                rh.count++;

                return 1;

            }

            return fullTryAcquireShared(current);

    }

 

final int fullTryAcquireShared(Thread current) {

            HoldCounter rh = cachedHoldCounter;

            if (rh == null || rh.tid != current.getId())

                rh = readHolds.get();

            for (;;) {

                int c = getState();

                int w = exclusiveCount(c);

                if ((w != 0 && getExclusiveOwnerThread() != current) ||

                    ((rh.count | w) == 0 && readerShouldBlock(current)))

                    return -1;

                if (sharedCount(c) == MAX_COUNT)

                    throw new Error( "Maximum lock count exceeded"

0
0
分享到:
评论

相关推荐

    Java 多线程与并发(10-26)-JUC锁- 锁核心类AQS详解.pdf

    它是实现Java并发包中锁和其他同步器的基础框架,例如ReentrantLock(可重入锁)、Semaphore(信号量)、CountDownLatch(倒计时门闩)、CyclicBarrier(循环栅栏)以及ReentrantReadWriteLock(可重入读写锁)等。...

    狂神说JUC代码狂神说JUC代码

    在Java中,JUC(java.util.concurrent)包包含了多种并发控制和同步工具,如线程池、锁、并发容器等,这些工具使得开发者能够编写高效、安全、可维护的并发代码。以下将详细讲解其中的一些关键知识点: 1. **线程池...

    Java 多线程与并发(12-26)-JUC锁- ReentrantReadWriteLock详解.pdf

    - AQS维护了一个32位的state变量,ReentrantReadWriteLock利用这个变量的高16位表示读锁的重入次数,低16位表示写锁的重入次数。 3. **读锁和写锁的最大数量** - 由于state变量的范围是32位,理论上读锁和写锁的...

    Java volatile与AQS锁内存可见性

    从JUC中的AQS引入,讲解Java volatile与AQS锁内存可见性

    JUC AQS的加解锁.pdf

    Java的并发编程是多线程和多任务处理的核心技术之一,而在Java并...开发者可以基于AQS创建复杂的同步结构,满足各种并发场景的需求。理解AQS的工作原理,对于使用Java并发包以及开发高性能的多线程应用具有重要的意义。

    juc aqs java

    juc 的aqs介绍。

    个人学习JUC代码笔记总集

    这个压缩包文件“个人学习JUC代码笔记总集”显然是一个个人的学习资源,记录了对JUC组件的理解和应用实例,特别适合已经有一定Java基础,想要深入学习并发编程的开发者。 JUC的主要目标是简化并发编程,提高多线程...

    java并发编程:juc、aqs

    AQS通过内部维护一个基于链表的等待队列,有效地管理线程的同步和唤醒,从而实现锁和其他同步原语。 **AQS核心特性:** 1. **资源管理**:AQS定义了两种资源获取方式:独占和共享。独占模式下,只有一个线程能访问...

    这就是标题—— JUC.pdf

    ReentrantReadWriteLock (读写锁) BlockingQueue(阻塞队列) 线程池 池化技术 线程池的优势 线程池的特点 线程池三大方法 线程池七大参数 线程池四种拒绝策略 ForkJoin 异步回调 Volatile 指令重排 JMM

    JUC(一)-AQS源码分析

    AQS源码分析一、锁的介绍1.1 乐观锁/悲观锁1.2 共享锁/独占锁1.3 公平锁/非公平锁1.4 小结二、AQS框架结构介绍2.1 类图2.2 AQS数据结构三、源码详解3.1 acquire源码详解3.2 release源码详解四、从ReentranLock看公平...

    JUC代码收集,java高并发多线程学习

    本资源"JUC代码收集,java高并发多线程学习"显然是一个专注于探讨和学习JUC库的资料包。 JUC库包含多个子包,如`concurrent`, `atomic`, `locks`等,每个子包都有其特定的功能和用途: 1. **concurrent**:这是JUC...

    JUC线程锁框架

    JUC中的锁机制包括ReentrantLock(可重入锁)、ReadWriteLock(读写锁)等。ReentrantLock相比synchronized具有更细粒度的控制,支持公平性和非公平性,并提供了tryLock()方法来尝试获取锁,以及lockInterruptibly...

    JUC核心类AQS的底层原理

    AQS作为Java并发工具包(JUC)中的一个核心抽象类,其设计目的是为了实现各种同步器(如锁、信号量等)。AQS主要通过三个核心组成部分来实现这些同步组件的功能: 1. **State变量及其CAS操作**:AQS维护了一个名为`...

    AQS和JUC知识点讲解

    《AQS和JUC知识点详解》 在Java并发编程领域,AbstractQueuedSynchronizer(AQS)和Java Util Concurrency(JUC)是两个至关重要的概念。它们为开发高效、线程安全的多线程程序提供了强大的工具。本文将深入解析这...

    JUC代码演示 Java多线程并发

    除了`synchronized`之外,Java还提供了更灵活的锁机制——`Lock`接口。`Lock`接口提供了比`synchronized`更强大的锁定机制,并且实现了更加精细的线程控制。 在示例中,使用了`ReentrantLock`类来实现自定义的锁: ...

    Java——JUC

    Java并发编程是Java开发中的重要领域,而Java并发工具包(Java Concurrency Utility,简称JUC)则是Java标准库提供的一套强大而丰富的工具,它极大地简化了多线程环境下的编程工作。JUC主要包含在`java.util....

    juc学习代码。。。。

    在这个"juc学习代码"的资源中,我们很显然会接触到Java并发编程的核心概念和实践。 首先,JUC库中的`java.util.concurrent`包包含了大量并发工具类,如`Semaphore`(信号量)、`CyclicBarrier`(循环屏障)、`...

    java并发编程-AQS和JUC实战

    ### Java并发编程-AQS和JUC实战 #### 一、ReentrantLock 重入锁 **1.1 概述** - **基本介绍**: `ReentrantLock` 是一个实现了 `Lock` 接口的可重入互斥锁,提供比 `synchronized` 更丰富的功能。与 `synchronized...

    juc并发编程脑图以及相关示例代码

    juc并发编程脑图以及相关示例代码

    JUC并发工具包实例.zip

    AQS是Java并发包中的核心抽象类,它是基于FIFO队列的等待锁框架。许多并发工具,如ReentrantLock、Semaphore等,都基于AQS实现。AQS维护了一个内部状态以及一个等待线程的双端队列,通过共享或独占模式来控制资源的...

Global site tag (gtag.js) - Google Analytics