Java多线程(六):J.U.C 之 AQS
Java 的内置锁一直都是备受争议的,在 JDK 1.6 之前,synchronized
这个重量级锁其性能一直都是较为低下,虽然在 1.6 后,进行大量的锁优化策略,但是与 Lock 相比 synchronized
还是存在一些缺陷的:虽然 synchronized
提供了便捷性的隐式获取锁释放锁机制(基于JVM机制),但是它却缺少了获取锁与释放锁的可操作性,可中断、超时获取锁,且它为独占式在高并发场景下性能大打折扣。
在介绍 Lock 之前,我们需要先熟悉一个非常重要的组件,掌握了该组件 J.U.C 包下面很多问题都不在是问题了。该组件就是 AQS 。
1. 简介
AQS ,AbstractQueuedSynchronizer ,即队列同步器。它是构建锁或者其他同步组件的基础框架(如 ReentrantLock、ReentrantReadWriteLock、Semaphore 等),J.U.C 并发包的作者(Doug Lea)期望它能够成为实现大部分同步需求的基础。
它是 J.U.C 并发包中的核心基础组件。
2. 优势
AQS 解决了在实现同步器时涉及当的大量细节问题,例如获取同步状态、FIFO 同步队列。基于 AQS 来构建同步器可以带来很多好处。它不仅能够极大地减少实现工作,而且也不必处理在多个位置上发生的竞争问题。
在基于 AQS 构建的同步器中,只能在一个时刻发生阻塞,从而降低上下文切换的开销,提高了吞吐量。同时在设计 AQS 时充分考虑了可伸缩性,因此 J.U.C 中,所有基于 AQS 构建的同步器均可以获得这个优势。
3. 同步状态
AQS 的主要使用方式是继承,子类通过继承同步器,并实现它的抽象方法来管理同步状态。
AQS 使用一个 int
类型的成员变量 state
来表示同步状态:
- 当
state > 0
时,表示已经获取了锁。 - 当
state = 0
时,表示释放了锁。
它提供了三个方法,来对同步状态 state
进行操作,并且 AQS 可以确保对 state
的操作是安全的:
#getState()
#setState(int newState)
#compareAndSetState(int expect, int update)
4. 同步队列
AQS 通过内置的 FIFO 同步队列来完成资源获取线程的排队工作:
- 如果当前线程获取同步状态失败(锁)时,AQS 则会将当前线程以及等待状态等信息构造成一个节点(Node)并将其加入同步队列,同时会阻塞当前线程
- 当同步状态释放时,则会把节点中的线程唤醒,使其再次尝试获取同步状态。
5. 主要内置方法
AQS 主要提供了如下方法:
#getState()
:返回同步状态的当前值。#setState(int newState)
:设置当前同步状态。#compareAndSetState(int expect, int update)
:使用 CAS 设置当前状态,该方法能够保证状态设置的原子性。- 【可重写】
#tryAcquire(int arg)
:独占式获取同步状态,获取同步状态成功后,其他线程需要等待该线程释放同步状态才能获取同步状态。 - 【可重写】
#tryRelease(int arg)
:独占式释放同步状态。 - 【可重写】
#tryAcquireShared(int arg)
:共享式获取同步状态,返回值大于等于 0 ,则表示获取成功;否则,获取失败。 - 【可重写】
#tryReleaseShared(int arg)
:共享式释放同步状态。 - 【可重写】
#isHeldExclusively()
:当前同步器是否在独占式模式下被线程占用,一般该方法表示是否被当前线程所独占。 acquire(int arg)
:独占式获取同步状态。如果当前线程获取同步状态成功,则由该方法返回;否则,将会进入同步队列等待。该方法将会调用可重写的#tryAcquire(int arg)
方法;#acquireInterruptibly(int arg)
:与#acquire(int arg)
相同,但是该方法响应中断。当前线程为获取到同步状态而进入到同步队列中,如果当前线程被中断,则该方法会抛出InterruptedException 异常并返回。#tryAcquireNanos(int arg, long nanos)
:超时获取同步状态。如果当前线程在 nanos 时间内没有获取到同步状态,那么将会返回 false ,已经获取则返回 true 。#acquireShared(int arg)
:共享式获取同步状态,如果当前线程未获取到同步状态,将会进入同步队列等待,与独占式的主要区别是在同一时刻可以有多个线程获取到同步状态;#acquireSharedInterruptibly(int arg)
:共享式获取同步状态,响应中断。#tryAcquireSharedNanos(int arg, long nanosTimeout)
:共享式获取同步状态,增加超时限制。#release(int arg)
:独占式释放同步状态,该方法会在释放同步状态之后,将同步队列中第一个节点包含的线程唤醒。#releaseShared(int arg)
:共享式释放同步状态。
从上面的方法看下来,基本上可以分成 3 类:
- 独占式获取与释放同步状态
- 共享式获取与释放同步状态
- 查询同步队列中的等待线程情况
AQS 内部维护着一个 FIFO 队列,该队列就是 CLH 同步队列。
1. 简介
CLH 同步队列是一个 FIFO 双向队列,AQS 依赖它来完成同步状态的管理:
- 当前线程如果获取同步状态失败时,AQS则会将当前线程已经等待状态等信息构造成一个节点(Node)并将其加入到CLH同步队列,同时会阻塞当前线程
- 当同步状态释放时,会把首节点唤醒(公平锁),使其再次尝试获取同步状态。
2. Node
在 CLH 同步队列中,一个节点(Node),表示一个线程,它保存着线程的引用(thread
)、状态(waitStatus
)、前驱节点(prev
)、后继节点(next
)。其定义如下:
Node 是 AbstractQueuedSynchronizer 的内部静态类。
|
waitStatus
字段,等待状态,用来控制线程的阻塞和唤醒,并且可以避免不必要的调用LockSupport的#park(...)
和#unpark(...)
方法。。目前有 4 种:CANCELLED
SIGNAL
CONDITION
PROPAGATE
。- 实际上,有第 5 种,
INITAL
,值为 0 ,初始状态。 -
Java多线程(六):J.U.C 之 AQS相关推荐
- Java多线程闲聊(五):AQS
Java多线程闲聊(五):AQS 前言 今天的第二篇了,我肚子里也没有那么多的墨水,所以这第二篇的前言,就免了吧. 正文 AQS,AbstractQueueSynchronizer,是Java官方所提 ...
- 死磕Java并发:J.U.C之AQS:CLH同步队列
本文转载自公号:Java技术驿站 在上篇文章"死磕Java并发:J.U.C之AQS简介"中提到了AQS内部维护着一个FIFO队列,该队列就是CLH同步队列. CLH同步队列是一个F ...
- 【死磕Java并发】-----J.U.C之AQS:CLH同步队列
原文出处:https://www.cmsblogs.com/category/1391296887813967872 『chenssy』 在上篇博客[死磕Java并发]-----J.U.C之AQS:A ...
- 死磕Java并发:J.U.C之AQS阻塞和唤醒线程
借此祝大家端午快乐 趁3天假期好好休息下 比如睡个懒觉,陪陪父母小孩等等 合理安排好自己的时间 让自己充分享受到假期的闲适 本文转载自公众号: Java技术驿站 回归主题: 在线程获取同步状态时如果获 ...
- 死磕Java并发:J.U.C之AQS同步状态的获取与释放
本文转载自公号:Java技术驿站 在前面提到过,AQS是构建Java同步组件的基础,我们期待它能够成为实现大部分同步需求的基础.AQS的设计模式采用的模板方法模式,子类通过继承的方式,实现它的抽象方法 ...
- 死磕Java并发:J.U.C之AQS简介
本文转载自公众号: Java技术驿站 Java的内置锁一直都是备受争议的,在JDK 1.6之前,synchronized这个重量级锁其性能一直都是较为低下,虽然在1.6后,进行大量的锁优化策略(死磕J ...
- Java多线程闲聊(六):synchronized关键字
Java多线程闲聊(六):synchronized关键字 前言 这篇文章我会在博客置顶,为什么呢?因为,三篇引用的文章写得太好了,我害怕后面找不到,看不到,然后忘了! 让我想想,感觉昨天的前言把最近肚 ...
- Java多线程系列(十):源码剖析AQS的实现原理
在并发编程领域,AQS号称是并发同步组件的基石,很多并发同步组件都是基于AQS实现,所以想掌握好高并发编程,你需要掌握好AQS. 本篇主要通过对AQS的实现原理.数据模型.资源共享方式.获取锁的过程, ...
- Java多线程系列之J.U.C并发包概述
J.U.C包简介 J.U.C并发包,即java.util.concurrent包,是JDK的核心工具包,是JDK1.5之后,由 Doug Lea实现并引入. 整个java.util.concurren ...
- Java多线程进阶(一)—— J.U.C并发包概述
本文首发于一世流云专栏: https://segmentfault.com/blog... J.U.C包简介 J.U.C并发包,即java.util.concurrent包,是JDK的核心工具包,是J ...
最新文章
- 小程序多个echars_微信小程序中使用echarts以及踩坑总结
- ASP.NET 2.0应用程序安全强化纵览
- uni-app/微信小程序:验证手机号 身份证 邮箱(正则表达式)
- 集成JavaFX和Swing
- 计算机网络自顶向下-应用层
- 用 C++ 跟你聊聊“桥接模式” | 原力计划
- Uva 11491 暴力贪心
- [原]MS SQL表字段自增相关的脚本
- CentOS 某服务器搭建问题收集
- 小红书口碑营销怎么做?小红书笔记结构剖析及场景营销
- XXL之整合SpringBoot
- 尽挥洒最终版 思嫣_温州方言歌曲_温州话歌曲
- 那些令人虎躯一震的排序算法MATLAB实现
- 从初级到资深:程序员的职业生涯思考与可迁移技能培养
- 香港虚拟主机空间哪个好?
- Github标星的Chrome 插件,开发者必备
- java弦截法,国家计算机软考高级程序员历年真题1996
- 受制裁,即 Github 之后,Adobe 也开始大量封禁账号和服务了!
- 人脸识别方案(包含tcp ,http,socket 三者的区别)
- 二极管、三极管在实际使用中的理解
热门文章
- Java多线程闲聊(五):AQS
- 实际上,有第 5 种,