深度解析Java 8:AbstractQueuedSynchronizer的实现分析(下)

DeepSeek-Coder v2.5在ERP二次开发中的本地化代码生成实践 ERP二次开发本质是将业务规则转化为跨层(数据库、服务、前端)的可运行逻辑,其核心挑战在于代码分散、规范严苛、环境封闭。AI辅助开发并非替代程序员,而是通过理解Spring Boot、MyBatis、SQL Server等企业级技术栈,将需求精准映射为符合编码规范与事务约束的Java/SQL/Vue三件套。DeepSeek-Coder v2.5凭借对ERP常用注解、枚举语义SQL、CI/CD就绪输出的专项优化,成为少有的能在本地离线运行、零依赖云服务的生产力工具。它适用于金蝶K3、鼎捷U9、用友BOS等主流 阅读详情

前言

经过本系列的上半部分JDK1.8 AbstractQueuedSynchronizer的实现分析(上)的解读,相信很多读者已经对AbstractQueuedSynchronizer(下文简称AQS)的独占功能了然于胸,那么这次我们通过对另一个工具类:CountDownLatch的分析来解读AQS的另外一个功能:共享功能。

AQS共享功能的实现

在开始解读AQS的共享功能前,我们再重温一下CountDownLatch,CountDownLatch为java.util.concurrent包下的计数器工具类,常被用在多线程环境下,它在初始时需要指定一个计数器的大小,然后可被多个线程并发的实现减1操作,并在计数器为0后调用await方法的线程被唤醒,从而实现多线程间的协作。它在多线程环境下的基本使用方式为:

//main thread
      // 新建一个CountDownLatch,并指制定一个初始大小
      CountDownLatch countDownLatch = new CountDownLatch(3);
      // 调用await方法后,main线程将阻塞在这里,直到countDownLatch 中的计数为0 
      countDownLatch.await();
      System.out.println("over");

     //thread1
     // do something 
     //...........
     //调用countDown方法,将计数减1
      countDownLatch.countDown();


     //thread2
     // do something 
     //...........
     //调用countDown方法,将计数减1
      countDownLatch.countDown();

       //thread3
     // do something 
     //...........
     //调用countDown方法,将计数减1
      countDownLatch.countDown();


注意,线程thread 1,2,3各自调用 countDown后,countDownLatch 的计数为0,await方法返回,控制台输入“over”,在此之前main thread 会一直沉睡。

可以看到CountDownLatch的作用类似于一个“栏栅”,在CountDownLatch的计数为0前,调用await方法的线程将一直阻塞,直到CountDownLatch计数为0,await方法才会返回,

而CountDownLatch的countDown()方法则一般由各个线程调用,实现CountDownLatch计数的减1。

知道了CountDownLatch的基本使用方式,我们就从上述DEMO的第一行new CountDownLatch(3)开始,看看CountDownLatch是怎么实现的。

首先,看下CountDownLatch的构造方法:

和ReentrantLock类似,CountDownLatch内部也有一个叫做Sync的内部类,同样也是用它继承了AQS。

再看下Sync:

如果你看过本系列的上半部分,你对setState方法一定不会陌生,它是AQS的一个“状态位”,在不同的场景下,代表不同的含义,比如在ReentrantLock中,表示加锁的次数,在CountDownLatch中,则表示CountDownLatch的计数器的初始大小。

设置完计数器大小后CountDownLatch的构造方法返回,下面我们再看下CountDownLatch的await()方法:

调用了Sync的acquireSharedInterruptibly方法,因为Sync是AQS子类的原因,这里其实是直接调用了AQS的acquireSharedInterruptibly方法:

从方法名上看,这个方法的调用是响应线程的打断的,所以在前两行会检查下线程是否被打断。接着,尝试着获取共享锁,小于0,表示获取失败,通过本系列的上半部分的解读, 我们知道AQS在获取锁的思路是,先尝试直接获取锁,如果失败会将当前线程放在队列中,按照FIFO的原则等待锁。而对于共享锁也是这个思路,如果和独占锁一致,这里的tryAcquireShared应该是个空方法,留给子类去判断:

再看看CountDownLatch:

如果state变成0了,则返回1,表示获取成功,否则返回-1则表示获取失败。

看到这里,读者可能会发现, await方法的获取方式更像是在获取一个独占锁,那为什么这里还会用tryAcquireShared呢?

回想下CountDownLatch的await方法是不是只能在主线程中调用?答案是否定的,CountDownLatch的await方法可以在多个线程中调用,当CountDownLatch的计数器为0后,调用await的方法都会依次返回。 也就是说可以多个线程同时在等待await方法返回,所以它被设计成了实现tryAcquireShared方法,获取的是一个共享锁,锁在所有调用await方法的线程间共享,所以叫共享锁。

回到acquireSharedInterruptibly方法:

如果获取共享锁失败(返回了-1,说明state不为0,也就是CountDownLatch的计数器还不为0),进入调用doAcquireSharedInterruptibly方法中,按照我们上述的猜想,应该是要将当前线程放入到队列中去。

在这之前,我们再回顾一下AQS队列的数据结构:AQS是一个双向链表,通过节点中的next,pre变量分别指向当前节点后一个节点和前一个节点。其中,每个节点中都包含了一个线程和一个类型变量:表示当前节点是独占节点还是共享节点,头节点中的线程为正在占有锁的线程,而后的所有节点的线程表示为正在等待获取锁的线程。如下图所示:

黄色节点为头节点,表示正在获取锁的节点,剩下的蓝色节点(Node1、Node2、Node3)为正在等待锁的节点,他们通过各自的next、pre变量分别指向前后节点,形成了AQS中的双向链表。每个线程被加上类型(共享还是独占)后便是一个Node, 也就是本文中说的节点。

再看看doAcquireSharedInterruptibly方法:

private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED); 
//将当前线程包装为类型为Node.SHARED的节点,标示这是一个共享节点。
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
//如果新建节点的前一个节点,就是Head,说明当前节点是AQS队列中等待获取锁的第一个节点,
//按照FIFO的原则,可以直接尝试获取锁。
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r); 
//获取成功,需要将当前节点设置为AQS队列中的第一个节点,这是AQS的规则//队列的头节点表示正在获取锁的节点
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) && //检查下是否需要将当前节点挂起
                    parkAndCheckInterrupt()) 
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }


这里有几点需要说明的:

1. setHeadAndPropagate方法:

首先,使用了CAS更换了头节点,然后,将当前节点的下一个节点取出来,如果同样是“shared”类型的,再做一个"releaseShared"操作。

看下doReleaseShared方法:

for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) { 
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) 
//如果当前节点是SIGNAL意味着,它正在等待一个信号,  
//或者说,它在等待被唤醒,因此做两件事,1是重置waitStatus标志位,2是重置成功后,唤醒下一个节点。
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))  
//如果本身头节点的waitStatus是出于重置状态(waitStatus==0)的,将其设置为“传播”状态。
//意味着需要将状态向后一个节点传播。
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }


为什么要这么做呢?这就是共享功能和独占功能最不一样的地方,对于独占功能来说,有且只有一个线程(通常只对应一个节点,拿ReentantLock举例,如果当前持有锁的线程重复调用lock()方法,那根据本系列上半部分我们的介绍,我们知道,会被包装成多个节点在AQS的队列中,所以用一个线程来描述更准确),能够获取锁,但是对于共享功能来说。

共享的状态是可以被共享的,也就是意味着其他AQS队列中的其他节点也应能第一时间知道状态的变化。因此,一个节点获取到共享状态流程图是这样的:

比如现在有如下队列:

当Node1调用tryAcquireShared成功后,更换了头节点:

     Node1变成了头节点然后调用unparkSuccessor()方法唤醒了Node2、Node2中持有的线程A出于上面流程图的park node的位置,

线程A被唤醒后,重复黄色线条的流程,重新检查调用tryAcquireShared方法,看能否成功,如果成功,则又更改头节点,重复以上步骤,以实现节点自身获取共享锁成功后,唤醒下一个共享类型节点的操作,实现共享状态的向后传递。

2.其实对于doAcquireShared方法,AQS还提供了集中类似的实现:

分别对应了:

  1. 带参数请求共享锁。 (忽略中断)
  2. 带参数请求共享锁,且响应中断。(每次循环时,会检查当前线程的中断状态,以实现对线程中断的响应)
  3. 带参数请求共享锁但是限制等待时间。(第二个参数设置超时时间,超出时间后,方法返回。)

比较特别的为最后一个doAcquireSharedNanos方法,我们一起看下它怎么实现超时时间的控制的。

因为该方法和其余获取共享锁的方法逻辑是类似的,我用红色框圈出了它所不一样的地方,也就是实现超时时间控制的地方。

可以看到,其实就是在进入方法时,计算出了一个“deadline”,每次循环的时候用当前时间和“deadline”比较,大于“dealine”说明超时时间已到,直接返回方法。

注意,最后一个红框中的这行代码:

nanosTimeout > spinForTimeoutThreshold


从变量的字面意思可知,这是拿超时时间和超时自旋的最小作比较,在这里Doug Lea把超时自旋的阈值设置成了1000ns,即只有超时时间大于1000ns才会去挂起线程,否则,再次循环,以实现“自旋”操作。这是“自旋”在AQS中的应用之处。

看完await方法,我们再来看下countDown()方法:

调用了AQS的releaseShared方法,并传入了参数1:

同样先尝试去释放锁,tryReleaseShared同样为空方法,留给子类自己去实现,以下是CountDownLatch的内部类Sync的实现:

死循环更新state的值,实现state的减1操作,之所以用死循环是为了确保state值的更新成功。

从上文的分析中可知,如果state的值为0,在CountDownLatch中意味:所有的子线程已经执行完毕,这个时候可以唤醒调用await()方法的线程了,而这些线程正在AQS的队列中,并被挂起的,

所以下一步应该去唤醒AQS队列中的头节点了(AQS的队列为FIFO队列),然后由头节点去依次唤醒AQS队列中的其他共享节点。

如果tryReleaseShared返回true,进入doReleaseShared()方法:

private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) { 
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0)) 
//如果当前节点是SIGNAL意味着,它正在等待一个信号,
 //或者说,它在等待被唤醒,因此做两件事,1是重置waitStatus标志位,2是重置成功后,唤醒下一个节点。
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))  
//如果本身头节点的waitStatus是出于重置状态(waitStatus==0)的,将其设置为“传播”状态。
//意味着需要将状态向后一个节点传播。
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
  }


当线程被唤醒后,会重新尝试获取共享锁,而对于CountDownLatch线程获取共享锁判断依据是state是否为0,而这个时候显然state已经变成了0,因此可以顺利获取共享锁并且依次唤醒AQS队里中后面的节点及对应的线程。

总结

本文从CountDownLatch入手,深入分析了AQS关于共享锁方面的实现方式:

如果获取共享锁失败后,将请求共享锁的线程封装成Node对象放入AQS的队列中,并挂起Node对象对应的线程,实现请求锁线程的等待操作。待共享锁可以被获取后,从头节点开始,依次唤醒头节点及其以后的所有共享类型的节点。实现共享状态的传播。

这里有几点值得注意:

  1. 与AQS的独占功能一样,共享锁是否可以被获取的判断为空方法,交由子类去实现。
  2. 与AQS的独占功能不同,当锁被头节点获取后,独占功能是只有头节点获取锁,其余节点的线程继续沉睡,等待锁被释放后,才会唤醒下一个节点的线程,而共享功能是只要头节点获取锁成功,就在唤醒自身节点对应的线程的同时,继续唤醒AQS队列中的下一个节点的线程,每个节点在唤醒自身的同时还会唤醒下一个节点对应的线程,以实现共享状态的“向后传播”,从而实现共享功能。

以上的分析都是从AQS子类的角度去看待AQS的部分功能的,而如果直接看待AQS,或许可以这么去解读:

首先,AQS并不关心“是什么锁”,对于AQS来说它只是实现了一系列的用于判断“资源”是否可以访问的API,并且封装了在“访问资源”受限时将请求访问的线程的加入队列、挂起、唤醒等操作, AQS只关心“资源不可以访问时,怎么处理?”、“资源是可以被同时访问,还是在同一时间只能被一个线程访问?”、“如果有线程等不及资源了,怎么从AQS的队列中退出?”等一系列围绕资源访问的问题,而至于“资源是否可以被访问?”这个问题则交给AQS的子类去实现。

当AQS的子类是实现独占功能时,例如ReentrantLock,“资源是否可以被访问”被定义为只要AQS的state变量不为0,并且持有锁的线程不是当前线程,则代表资源不能访问。

当AQS的子类是实现共享功能时,例如:CountDownLatch,“资源是否可以被访问”被定义为只要AQS的state变量不为0,说明资源不能访问。

这是典型的将规则和操作分开的设计思路:规则子类定义,操作逻辑因为具有公用性,放在父类中去封装。

当然,正式因为AQS只是关心“资源在什么条件下可被访问”,所以子类还可以同时使用AQS的共享功能和独占功能的API以实现更为复杂的功能。

比如:ReentrantReadWriteLock,我们知道ReentrantReadWriteLock的中也有一个叫Sync的内部类继承了AQS,而AQS的队列可以同时存放共享锁和独占锁,对于ReentrantReadWriteLock来说分别代表读锁和写锁,当队列中的头节点为读锁时,代表读操作可以执行,而写操作不能执行,因此请求写操作的线程会被挂起,当读操作依次推出后,写锁成为头节点,请求写操作的线程被唤醒,可以执行写操作,而此时的读请求将被封装成Node放入AQS的队列中。如此往复,实现读写锁的读写交替进行。

而本系列文章上半部分提到的FutureTask,其实思路也是:封装一个存放线程执行结果的变量A,使用AQS的独占API实现线程对变量A的独占访问,判断规则是,线程没有执行完毕:call()方法没有返回前,不能访问变量A,或者是超时时间没到前不能访问变量A(这就是FutureTask的get方法可以实现获取线程执行结果时,设置超时时间的原因)。

综上所述,本系列文章从AQS独占锁和共享锁两个方面深入分析了AQS的实现方式和独特的设计思路,希望对读者有启发,下一篇文章,我们将继续JDK 1.8下 J.U.C (java.util.concurrent)包中的其他工具类,敬请期待。

Qemu开发ARM篇-3、qemu运行uboot演示 在上一篇文章中,我们搭建了交叉编译工具链,并成功进行了uboot的交叉编译,在该篇中,我们将演示如何利用qemu运行上一篇中交叉编译的uboot程序。 阅读详情

相关推荐

计算机视觉-深度学习图像检测方法梳理

计算机视觉-深度学习图像检测方法梳理 由于之后要转方向啦,趁这段时间整理手中硕士研究方向的一些阅读笔记,这是一篇关于计算机视觉的基础知识梳理 先搞清一些小知识点 首先我们要弄清楚图像分类、目标定位、语义分割、实例分割的区别 a. 图像分类 :给定一张输入图像,图像分类任务旨在判断该图像所属类别; b. 目标定位 :在图像分类的基础上,我们还想知道图像中的目标具体在图像的什么位置,通常是以包围盒的(bounding box)形式; c. 语义分割 :语义分割是目标检测更进阶的任务,目标检测只需要框出每个目

qq_41662991的博客 9953

AbstractQueuedSynchronizer(AQS)超详细解析

JUC是jdk中专门处理线程的一个工具包,其中有一个非常重要的抽象类AbstractQueuedSynchronizer(AQS)。Lock、Condition都是基于AQS而开发的,本文将深入解析AQS的细节和原理。

benjam1n77的博客 5718

5分钟快速验证lvgl界面:VScode模拟器极简配置法(免环境变量版)

本文介绍了一种5分钟快速验证LVGL界面的极简配置方法,使用VSCode模拟器免环境变量配置,适合UI设计师和产品经理快速预览界面效果。通过预编译的SDL2库和配置好的VSCode工程模板,实现开箱即用的LVGL界面验证,大幅提升工作效率。

weixin_30790841的博客 314

让人头疼的AbstractQueuedSynchronizer究竟是什么?

FIFO双向链表,通过head节点和tail节点来记录队首和队尾元素,主要使用方式是继承,子类通过继承同步器并实现它的抽象方法来管理同步状态,可重写的方法tryAcquire(int arg)、tryRelease(int arg)、tryAcquireShared(int arg)、tryReleaseShared(int arg)、isHeldExclusively(),很多同步类都继承该类来实现同步逻辑,子类通过继承AQS并实现它的抽象方法来管理同步状态。,是一个抽象类,它是从java5开始的。

Lxn2zh的博客 1194

5G NR 帧结构

本节主要介绍5G NR中的帧结构[38.211-4.3]。5G帧结构(Frame Structure)为时域结构。其设计比其4G LTE更为灵活,这种灵活性使5G能够根据应用需求(如增强移动宽带eMBB,超高可靠低时延通信URLLC)进行调整,同时支持差异化的应用场景,提高了5G的利用效率与响应能力。具体而言,5G帧结构是基于时隙和OFDM符号设计的,且5G网络能够根据服务需求动态调整各时隙持续时长。

夫子喵的博客 5286

stm32教程之三重ADC交错采样

ps:本文基于stm32F407ZGT6单片机 stm32F4单片机单通道采集的最大采样率为2.4M,所以有时会难以满足较高频率的采样,于是查阅芯片手册,发现stm32F4支持多重ADC采集,利用每个通道的转换时间,错位采样,从而提高采样率,最大把采样率开到2.4*3=7.2M. (去年初学ADC时研究的,基于cube和HAL库的三重ADC交错采样参考资料不多,我也是研究了一段时间,写下这篇博客希望可以帮助到更多人。) 示意图如下: 以下是官方例子的说明, In this ex...

weixin_52178036的博客 8877

队列同步器AbstractQueuedSynchronizer

再说吧,没空写了

qq_45036591的博客 598

【中英双语】Illumina测序原理详解 | 边合成边测序/Sequencing by Synthesis

很多朋友们问我视频讲解时用的笔记可不可以分享,那当然必须是可以呐!但我当时其实没有好好记录,只是打了个草稿就开讲啦!既然大家有需求,俺就重新整理了一下,希望可以帮到大家!

weixin_43843918的博客 7872

AbstractQueuedSynchronizer 简介

AbstractQueuedSynchronizer(AQS)是 Java 并发包中的核心类,由 Doug Lea 编写,为多种同步工具(如 ReentrantLock、CountDownLatch 等)提供底层支持。AQS 通过一个 int 类型的 state 变量表示同步状态,结合 CAS 操作和 CLH 队列实现多线程的同步控制。它采用模板方法设计模式,定义了 tryAcquire、tryRelease 等抽象方法,由子类实现具体的同步语义。AQS 支持独占和共享两种模式,分别用于不同的并发场景。其核

红血哥 1079

2023华为od机试C卷【最富裕的小家庭】C语言 实现

在一颗树中,每个节点代表一个家庭成员,节点的数字表示其个人的财富值,一个节点及其直接相连的子节点被定义为个小家庭。现给你一颗树,请计算出最富裕的小家庭的财富和。

MISAYAONE的博客 500

低轨通信 | 手机直连低轨卫星通信:架构、关键技术与未来展望

手机直连低轨卫星通信正推动人类进入"全域连接"时代。当中国星网GW星座与千帆星座的万颗卫星点亮夜空,当普通智能手机在珠峰之巅仍能流畅视频通话,当远洋渔船通过卫星物联网实现精准捕捞——这些场景不仅重构通信产业格局,更将深刻改变人类生产生活方式。正如工信部《指导意见》所规划,到2030年我国将发展超千万卫星通信用户,催生万亿级新市场[1][5]。在这场太空基建竞赛中,技术创新与标准制定的双重突破,将决定未来数字文明的星空版图。

尘世冰封的专栏 939

java synchronizer_java并发编程之AbstractQueuedSynchronizer

引言AbstractQueuedSynchronizer,队列同步器,简称AQS,它是java并发用来构建锁或者其他同步组件的基础框架。一般使用AQS的主要方式是继承,子类通过实现它提供的抽象方法来管理同步状态,主要管理的方式是通过tryAcquire和tryRelease类似的方法来操作状态,同时,AQS提供以下线程安全的方法来对状态进行操作:protected final int getSta...

weixin_39889481的博客 254

【MATLAB】工业传送带速度闭环控制与张力联合仿真

本文基于MATLAB/Simulink平台,构建了工业传送带速度闭环控制与张力联合仿真系统。通过搭建驱动模块、机械传动模块、检测模块和控制模块,实现了速度与张力的协同控制。采用双PID调节器分别整定速度与张力参数,经联合调试后系统性能良好:速度跟踪误差小于±0.03m/s,张力波动控制在±30N内,负载扰动恢复时间仅0.3秒。研究提供了从建模到参数优化的完整工程方案,可直接应用于课程设计或工业实践,有效解决了传送带运行中速度偏差与张力波动的协同控制难题。

unber的博客 78

深度解析Java 8:JDK1.8 AbstractQueuedSynchronizer的实现分析

https://www.jianshu.com/p/259780bb79f2

wangbaosongmsn的博客 133

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

深度解析Java8 – AbstractQueuedSynchronizer的实现分析(下)

本文首发在infoQ :http://www.infoq.com/cn/articles/java8-abstractqueuedsynchronizer,感谢作者liuinsect的分享。 前言:      经过本系列的上半部分JDK1.8 AbstractQueuedSynchronizer的实现分析(上)的解读,相信很多读者已经对AbstractQueuedSynchronize

zz87250976的专栏 439

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

深度解析Java8 – AbstractQueuedSynchronizer的实现分析(上)

本文首发在infoQ :www.infoq.com/cn/articles/jdk1.8-abstractqueuedsynchronizer 前言: Java中的FutureTask作为可异步执行任务并可获取执行结果而被大家所熟知,通常可以使用future.get()来获取线程的执行结果,在线程执行结束之前,get方法会一直阻塞状态,直到call()返回,其优点是使用线程异步执行任务的情

tianjinsong的专栏 4408

深度解析Java 8:JDK1.8 AbstractQueuedSynchronizer的实现分析(上)

前言 Java中的FutureTask作为可异步执行任务并可获取执行结果而被大家所熟知。通常可以使用future.get()来获取线程的执行结果,在线程执行结束之前,get方法会一直阻塞状态,直到call()返回,其优点是使用线程异步执行任务的情况下还可以获取到线程的执行结果,但是FutureTask的以上功能却是依靠通过一个叫AbstractQueuedSynchronizer的类来实现,

青色刀客的专栏 981

转:深度解析Java8 – AbstractQueuedSynchronizer的实现分析(上)

原文链接:http://www.liuinsect.com/2014/08/07/jdk1-8-abstractqueuedsynchronizer/ 前言: Java中的FutureTask作为可异步执行任务并可获取执行结果而被大家所熟知,通常可以使用future.get()来获取线程的执行结果,在线程执行结束之前,get方法会一直阻塞状态,直到call()返回,其优点是使用线程异步执行任务...

weixin_30239339的博客 92

java abstractqueue_深度解析Java8 – AbstractQueuedSynchronizer的实现分析(下)

本文首发在infoQ 作者:刘锟洋前言经过本系列的上半部分JDK1.8 AbstractQueuedSynchronizer的实现分析(上)的解读,相信很多读者已经对AbstractQueuedSynchronizer(下文简称AQS)的独占功能了然于胸,那么,这次我们再借助另一个工具类:CoutDownLatch,换个角度看看AQS的另外一个重要功能——共享功能的实现。AQS共享功能的实现...

weixin_36278243的博客 339
上一篇: 深度解析Java 8:JDK1.8 AbstractQueuedSynchronizer的实现分析(上)
下一篇: JDK1.8 AbstractQueuedSynchronizer的实现分析(学习笔记)
weiythi
博客等级 码龄16年 23粉丝 48原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值