多线程:AQS的一些心得
AQS作为JUC并发组件实现的核心。全称是AbstructQueuedSynchronizer,也就是同步队列器。
其内部实现主要的是一个state状态标识和基于FIFO一个同步队列。
这个状态标识表明当前的资源是否是可以争取的,当state=0是,表示资源没有加锁;当state>0时,表示资源加锁。
关于这个队列,有几个属性:
1)队列是基于双向链表的,因此具有定制的节点结构信息。node
2)tail尾指针,指向队列的最后一个节点
3)头指针,指向队列的第一个节点(也即是 头节点)。头结点中包含有当前资源的同步状态信息。
4)waitStatus 节点等待标识。
=1时 SIGNAL 表明当前节点的后继节点所包含的线程需要运行。
=-1 CANCEL 表明当前节点线程取消
=-2 CONDITION 表明当前节点在等待condition 处于Condition等待队列
=-3 PROPAGATE 应用在共享锁中
= 0 当前节点在同步队列中,等待获取锁
AQS是通过内部的同步队列来完成线程获取资源的排队工作
AQS可以实现独占锁和共享锁。
ReentrantLock实现的是独占锁;ReentrantReadWriteLock实现的是独占锁和共享锁;CountDownLatch实现的是共享锁。
因此,关于锁的获取和释放有以下几种方式:
1)独占式获取锁
首先,线程尝试获得锁tryAcquire,获取成功则函数返回,获得失败,addWaiter构造一个独占模式同步节点,如果前驱节点不为空则将该节点采用CAS方式放置到同步队列尾部,如果放置失败则说明当前节点位置存在并发竞争,进入enq方法进行添加,其实,enq方法也就是通过CAS自旋锁的方式不断地尝试来向队列中添加构造的节点;
如果节点最后成功地放置到队列里。执行acquireQueued方法,当前节点中的线程通过自旋方式尝试获取同步状态。
如果当前节点的前驱节点是头结点,并且重新尝试获取锁成功,就将当前节点设置为头结点!否则判断当前线程是否可以被安全阻塞挂起(根据waitStatus来判断,判断函数shouldParkAfterFailedAcquire),是的话就调用parkAndCheckInterrupt方法里的park方法进行挂起。然后再次进入for循环自旋。
如何判断????
当前节点的前驱节点是waitStatus是SIGNAL则可以挂起,之后由前驱节点进行唤醒;
若前驱节点是CANCEL 则向前遍历直到找到一个是SIGNAL的节点,并将当前节点放置在此节点的后面,不能挂起;
否则尝试将前驱节点的状态设置为SIGNAL,不能挂起
2)独占式释放锁
调用release方法来释放锁。这个方法一般由子类自己重写。
首先,尝试释放锁tryRelease,如果成功那么就唤醒后继节点 unparkSuccessor里的LockSupport.unpark方法
3)共享式获得锁
调用acquireShared方法,首先尝试获得锁,获得成功就返回;获得失败进入等待队列。直到获取到资源为止才返回。
若当前节点的前驱节点是头结点,则尝试进行加锁;如果加锁成功就调用setHeadAndPropagate,将当前节点设置为头结点,唤醒后继节点,并将之前的头结点从队列中踢出去,等待GC回收;
shared模式下是允许多个线程持有一把锁的,其中tryAcquire的返回值标志了是否允许其他线程继续进入。如果允许的话,需要唤醒队列中等待的线程。其中setHeadAndPropagate方法中的doReleaseShared方法的逻辑很简单,就是唤醒后继线程。
如果获得锁失败,判断当前线程是否可以被安全阻塞挂起,是的话就调用parkAndCheckInterrupt方法里的park方法进行挂起。
tryAcquireShared返回值为正,说明获得锁成功,负数则失败。
4)共享式释放锁
调用releaseShared方法;尝试释放锁,释放成功再次调用doReleaseShared,此方法内部还是调用LockSupport.unpark()方法唤醒后继线程。
5)独占超时获得锁
相比于独占获得锁方式,最重要的区别就是:独占获得锁在自旋获得锁失败之后会挂起,让出CPU时间片,之后再次进入for循环自旋尝试获得锁;而独占超时获得锁在获得锁失败之后,判断当前时间是否超时?若超时,则直接返回不再进行for循环;若没有超时,则将当前线程阻塞指定的超时时间之后再次进行for循环进行CAS自旋获取锁!
调用doAcquireNanos方法。该方法在自旋过程中,当节点的前驱节点为头节点时尝试获取同步状态,如果获取成功则从该方法返回,这个过程和独占式同步获取的过程类似,
但是在同步状态获取失败的处理上有所不同。如果当前线程获取同步状态失败,则首先重新计算超时间隔nanosTimeout,则判断是否超时(nanosTimeout小于等于0表示已经超时),如果没有超时,则使当前线程等待nanosTimeout纳秒(当已到设置的超时时间,该线程会从LockSupport.parkNanos(Object blocker,long nanos)方法返回)。
如果nanosTimeout小于等于spinForTimeoutThreshold(1000纳秒)时,将不会使该线程进行超时等待,而是进入快速的自旋过程。原因在于,非常短的超时等待无法做到十分精确,如果这时再进行超时等待,相反会让nanosTimeout的超时从整体上表现得反而不精确。因此,在超时非常短的场景下,同步器会进入无条件的快速自旋。
详情请参见本博客多线程模块AQS源码分析文章
多线程:AQS的一些心得相关推荐
- Java多线程 - AQS详解
介绍 AQS是java.util.concurrent.locks下类AbstractQueuedSynchronizer的简称,是用于 通过Java源码来构建多线程的锁和同步器的一系列框架,用于Ja ...
- 多线程—AQS独占锁与共享锁原理
java.util.concurrent.locks包下,包含了多种锁,ReentrantLock独占锁.ReentrantReadWriteLock读写锁等,还有java.util.concurre ...
- Java 多线程 —— AQS 详解
引言 AQS 是AbstractQuenedSynchronizer 的缩写,抽象的队列式同步器,它是除了java自带的synchronized关键字之外的锁机制.是 JUC 下的重要组件. 相关产物 ...
- java多线程aqs实现工具类_Java并发多线程 - 并发工具类JUC
(adsbygoogle = window.adsbygoogle || []).push({}); 安全共享对象策略 1.线程限制 : 一个被线程限制的对象,由线程独占,并且只能被占有它的线程修改 ...
- linux c 多线程socket编程,Linux多线程socket编程一些心得
前段时间将新的web模型办到Linux上来,用epoll代替了IOCP,经测试确实性能提高了很多,吞吐量也寓所提高,对于Linux下面的网络编程不是三言两语就能说得透的了,加上多线程就更麻烦了,但是e ...
- Java 多线程 —— AQS 原理
引言 使用Condition实现生产者-消费者模型,并与wait和notify实现的效果相对比. wait/notify模拟生产者-消费者 面试题:写一个固定容量同步容器,拥有put和get方法,以及 ...
- python多线程填写体温(一次可填写10+位+含双验证码填写)----升级至尊版
继上次教程:利用python制作自动填写体温程序最详细教程来了(有后续哦) {注意:代码已经无法运行,仅做参考} 需要完整代码的同学看目录自取,也可以加强学习,大家一起学习交流呀! 温馨提示:本代码仅 ...
- JAVA后端面经总结
JAVA后端开发知识总结(持续更新-) JAVA后端面经总结 文章目录 JAVA后端面经总结 一.JAVA基础 一.1.设计模式 二.MySQL 三.多线程 五.Redis 六(1).计算机网络 六( ...
- 尚硅谷Java第三季--1.javaj基础
1. javaj基础 Java字符串常量池 public class StringPools58Demo {public static void main(String[] args) {/*(1). ...
最新文章
- c++后台开发项目_[c/c++后台开发面经系列]4 Zoom面经(含答案)
- 打开word或者office程序报错:Microsoft Visual C++ Runtime Library. Runtime Error!
- PHP 5.6.32 增加pdo_dblib.so拓展
- 获取程序代码块资源消耗
- Java泛型总结--转
- 极大似然估计的朴素理解
- Vue+Openlayers+el-checkbox实现多选配置图层的显示和隐藏
- oauth2 access_denied 不允许访问_OAuth 2 是什么-入门介绍
- 架构设计中的方法学(七)
- 全栈工程师薪水_2020 Java 全栈工程师进阶路线图,不可错过
- Typecho安装后后台界面和文章链接均为404错误的解决方法
- STL的Vector介绍
- 基于mpvue的toast组件
- stochastic noise and deterministic noise
- 记录-如何测试服务器是否支持ipv6
- C++ vector 和push_back 详解
- 其实,我对你是有一些失望的。
- 制图操作案例:在Pro画水墨画
- 基于独立工作流引擎实现的SuperFlow工作流平台设计方案
- nginx 配置优化的几个参数