Java并发同步器AQS(AbstractQueuedSynchronizer)学习笔记(1)

Java中的并发包,是在Java代码中并发程序的热门话题。如果我们去读concurrent包的源码时,会发现其真正的核心是 AbstractQueuedSynchronizer , 简称 AQS 框架 , 而 Doug Lea 大神正是此包的作者。

之前也看过一遍 AbstractQueuedSynchronize,但印象不深,只有依稀的印象。这次重新学习一遍,并整理出笔记,希望对自己或者是别人有用。当然了,笔者也是浅显的过一遍,很多细节也并不是完全理解。

建议读者先看这个系列的文章:Inside AbstractQueuedSynchronizer,之后再继续本篇。

首先,AQS会对进行 acquire 而被阻塞的线程进行管理,说是管理,其实就是内部维护了一个FIFO队列,这个队列是一个双向链表。链头可以理解为是一个空的节点,除了链头以外,每个节点内部都持有着一个线程,同时,有着两个重要的字段:waitStatus 和 nextWaiter。nextWaiter一般是作用与在使用Condition时的队列。而waitStatus则有以下几个字段:

  • SIGNAL 表示下一个节点应该被唤醒。为什么是下一个节点?因为刚刚说了,这个FIFO队列,链头都是一个空的节点,但此节点的 waitStatus 正好就表示了要对下一节点做的事情

  • CANCELLED 表示此节点持有的线程被中断,或者该线程为null了。节点只能是暂时停留在此状态,因为在线程进入AQS时,线程会找机会整理链表,包括删除CANCELLED状态的节点。

  • CONDITION 表示此节点是在另一个队列中 —— condition队列中。比如我们使用的ReentrantLock.newCondition()获得Condition对象进行await时,在AQS内部所产生的节点。

  • PROPAGATE 顾名思义,传播。这点比较难理解,需要仔细推敲。因为此状态是为共享同步器使用的。加入此状态,可以避免无谓的线程 park 和 unpark。按照我对代码的理解,这是对多个线程并发获取共享同步器(比如acquireShared)所进行的优化,至少有3个线程并发,但想要优化效果明显的话,可能需要几十个线程并发的获取共享同步器(比如acquireShared),如果在并发量非常大的时候,对系统的吞吐量的作用应该不少。

AbstractQueuedSynchronizer内置一个state字段,用来表示某种意义——当ReentrantLock使用AQS的时候,state被用来表示锁被重入的次数;当’Semaphore’使用AQS的时候,state则被用来表示当前还有多少信号量可被获取。

AbstractQueuedSynchronizer 支持两种模式,分别是独占式和共享式。两者进行获取和释放动作的思路都是差不多的。

获取同步器的流程如下:

1<!-- lang: java --> 2if(尝试获取成功){ 3 return4 }else{ 5 加入等待队列;park自己 6}

释放同步器的流程如下:

1<!-- lang: java --> 2if(尝试释放成功){ 3 unpark等待队列中第一个节点 4}else{ 5 return false 6}

只要环绕着这两个思路去看AQS中的代码,相信应该可以明白其中的主要原理。

原文在我的博客上:Java并发同步器AQS(AbstractQueuedSynchronizer)学习笔记(1)

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java高并发核心类 AQS(Abstract Queued Synchronizer)抽象队列同步器

什么是AQS?全称:AbstractQueuedSynchronizer:抽象队列同步器是java.util.concurrent.locks包下的一个抽象类其编写者:DougLea(并发大佬,整个j.u.c包都是他写的)是j.u.c包的基础组件(核心)我们先来读一下该类的英文说明注