一 AQS简介

路径:java.util.concurrent.locks.AbstractOwnableSynchronizer。

定义:AQS提供了一种 通过维护一个volatile修饰 int类型 state 和 一个FIFO等待队列(双向链表实现)来实现锁功能 的同步器的框架。

描述:队列同步器AQS,抽象类,是用来构建 和synchronized类似效果的锁(或称同步组件)的基础框架,主要使用方法就是继承它,然后实现抽象方法来维护state ,如 ReentrantLock(内部类继承的)就是基于AQS实现的。

二 核心

核心方法:同步器提供acquire()和release()两个方法,见名知意,一个方法时获取同步状态,一个是释放,所以这个关键就是操作state。

public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
public final boolean release(int arg) {
if (tryRelease(arg)) {//同步状态释放成功
Node h = head;
if (h != null && h.waitStatus != 0)
//直接释放头节点
unparkSuccessor(h);
return true;
}
return false;
}

主要实现方法:tryAcquire(int arg) 和 tryRelease(int arg)也就是上面的acquire和release中调用的,这里的我们需要完成具体实现。tryAcquire(int arg)就是去获取state,改变他的值,tryRelease(int arg)这里就是释放state。

AQS类结构:

主要成员                        图1

1: state,这是线程之间争夺的资源,也可以称同步状态,改变他的值意味着获取或者释放锁。

提供3个CAS操作来操作这个同步状态

  • getState()
  • setState()
  • compareAndSetState()

2:Node head 和Node tail  指向头结点和尾结点,用来操作双向链表的。

3:内部类Node,双向链表的节点,双向链表实现其实就是Node 里面设置两个 Node的引用

static final class Node {
  Node next;  下一个节点
  Node pre;   前一个节点 
  Thread thread;  当前线程
  int waitState;   当前node节点的状态,和上面说的同步状态state无关。
  Node nextWaiter;后面说道
}

4:内部类ConditionObject,用来操作同步期的等待队列的,就相当于synchronized的等待队列,用的是Object的wait()和notify(),而aqs用的则是ConditionObject对象。

三:整合

1:首先调用的线程A会去执行acquire()这个方法,如果tryAcquire()能够获取state(cas改变值),意味着获取到了锁,那么就可以直接执行A的代码了。

如果失败,会创建一个Node,把当前线程A set其中,链在 tail  尾结点上。接着就是一段自旋去尝试获取锁,直到当前node的pre前一个节点的waitState是指定状态(-1),线程a会被park()这个挂起线程的。这样就不会一直自旋了,解除挂起要么a被中断了,要么前面的节点会release了,会有一个唤醒后面节点的操作unpark。我这里描述的很简单,其实很复杂,要去看源码,参考其他https://www.cnblogs.com/iou123lg/p/9464385.html

public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}

2:一个aqs对象 对应着一个同步队列和多个等待队列,同步队列就是上面说的head和tail组成的,用来存放操作同步状态的 双向链表;而这里我要强调的是等待队列,它是依靠的是ConditionObject这个内部类

public class ConditionObject implements Condition
/** First node of condition queue. */
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;

这里可以看到继承上面的Node的,也就是也有一个nextWaiter字段,等待队列是一个单循环链表firstWaiter和lastWaiter指向头尾,nextWaiter指向下一个,结构就是如此。

等待队列的节点产生,一个aqs对象能 new 出多个Condition对象,也就意味着能够 有多个等待队列,每个Condition都对应一个等待队列

例如 condition1=new Condition(),当condition1.await()

Node node = addConditionWaiter();
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}

首先会根据当前线程创建一个Node节点放到condition1的链表中,让lastWaiter和firstWaiter都指向她。

然后会去释放资源,释放state,做一个减少操作。这里释放资源,意味着同步队列中的头结点要去掉,并且唤醒后面的节点。

接着 就是一段自循环,判断条件是判断同步队列中是否有这个node,如果没有,则挂起当前线程。如果有则重新去争夺state.正常来说这个新增在等待队列的node是不出现在同步队列中的,所以会挂起,除非调用了signal()方法,相当于Object的notify()

signal()

这个方法会去将condition1的等待队列中的firstWaiter 拿出来(也就是删除掉),然后把他再加入同步队列中,也就是从等待队列的头移到了同步队列的尾。

借鉴:

https://www.cnblogs.com/iou123lg/p/9464385.html

https://www.jianshu.com/p/da9d051dcc3d


  

AQS 入门的更多相关文章

  1. 深度分析ReentrantLock源码及AQS源码,从入门到入坟,建议先收藏!

    一.ReentrantLock与AQS简介 在Java5.0之前,在协调对共享对象的访问时可以使用的机制只有synchronized和volatile.Java5.0增加了一种新的机制:Reentra ...

  2. AQS简单理解入门---1

    这篇文章,我们来聊聊面试时一个比较有杀伤力的问题:聊聊你对AQS的理解? 之前有同学反馈,去互联网公司面试,面试官聊到并发时就问到了这个问题.当时那位同学内心估计受到了一万点伤害... 因为首先,很多 ...

  3. AQS快速入门

    一.模板方法模式 父子类多态,父类中用一个方法调用执行所有所需要的方法: 父类: 子类: 主线程执行时候调用父类的模板方法: 二.AQS思想 sync都是独占锁,lock显示锁也是,只有读写锁是共享锁 ...

  4. 4.从AbstractQueuedSynchronizer(AQS)说起(3)——AQS结语

    前两节的内容<2.从AbstractQueuedSynchronizer(AQS)说起(1)——独占模式的锁获取与释放> .<3.从AbstractQueuedSynchronize ...

  5. EasyUI学习(一)——EasyUI入门

    EasyUI学习总结(一)——EasyUI入门 一.EasyUI下载 EasyUI官方下载地址:http://www.jeasyui.com/download/index.php,目前最新的版本是:j ...

  6. Java高并发--AQS

    Java高并发--AQS 主要是学习慕课网实战视频<Java并发编程入门与高并发面试>的笔记 AQS是AbstractQueuedSynchronizer的简称,直译过来是抽象队列同步器. ...

  7. EasyUI总结(一)-- 入门

    一.EasyUI下载 EasyUI官方下载地址:http://www.jeasyui.com/download/index.php,目前最新的版本是:jQuery EasyUI 1.4.1

  8. 图解AQS的设计与实现,手摸手带你实现一把互斥锁!

    AQS是并发编程中非常重要的概念,它是juc包下的许多并发工具类,如CountdownLatch,CyclicBarrier,Semaphore 和锁, 如ReentrantLock, ReaderW ...

  9. 数论入门——斐蜀定理与拓展欧几里得算法

    斐蜀定理 内容 斐蜀定理又叫贝祖定理,它的内容是这样的: 若$a,bin N$,那么对于任意x,y,方程$ax+by=gcd(a,b)*k(kin N)$一定有解,且一定有一组解使$ax+by=gcd ...

随机推荐

  1. 前端深入之css篇|你真的了解“权重”吗?

    写在前面 权重这个概念,相信对许多进行过前端开发的小伙伴来说肯定并不陌生,有时候一个样式添加不上,我们就会一个 !important 怼上去,一切就好像迎刃而解了.但还有的时候,!important也 ...

  2. PHP7源码之array_flip函数分析

    以下源码基于 PHP 7.3.8 array array_flip ( array $array ) (PHP 4, PHP 5, PHP 7) array_flip - 交换数组中的键和值 arra ...

  3. XCTF-CAT

    果然还是我太菜了呜呜呜,这道题仍然是没有自己做出来.哎. 这一道用的并不是PHP的环境,而是用Python中的Django编写的. 记得做过类似的一道题目.来源于MOCTF中的网站扫描器,当时做完后其 ...

  4. 一文掌握在Word中快速编写公式

    在使用Word编写文章时,总会遇到书写数学公式的情况.使用Word的公式输入工具需要频繁地使用鼠标,因而编写公式会显得繁琐麻烦,那么有什么办法可以优雅地在Word中书写公式呢?其实Word早在Word ...

  5. MRP进程起不来, 报错:ORA-00600: internal error code, arguments: [2619], [227424], [], [], [], [], [], [], [], [], [], []

    问题背景:客户数据库服务架构为一主一备,某日备库操作系统意外重启,重启后Oracle MRP进程起不来,报错:ORA-00600: internal error code, arguments: [2 ...

  6. B-微积分-sign(符号)函数

    目录 sign(符号)函数 一.sign函数概述 二.python实现sign函数 更新.更全的<机器学习>的更新网站,更有python.go.数据结构与算法.爬虫.人工智能教学等着你:h ...

  7. Cocos Creator 通用框架设计 —— 网络

    在Creator中发起一个http请求是比较简单的,但很多游戏希望能够和服务器之间保持长连接,以便服务端能够主动向客户端推送消息,而非总是由客户端发起请求,对于实时性要求较高的游戏更是如此.这里我们会 ...

  8. java之ThreadLocal详解

    一.ThreadLocal简介 ThreadLocal是线程的局部变量,是每一个线程所单独持有的,其他线程不能对其进行访问,通常是类中的private static字段. 我们知道有时候一个对象的变量 ...

  9. net core WebApi——使用NPOI导入导出操作

    目录 前言 NPOI 测试 小结 @ 前言 时间过得好快,在之前升级到3.0之后,就感觉好久没再动过啥东西了,之前有问到Swagger的中文汉化,虽说我觉得这种操作的意义不是太大,也是多少鼓捣了下,其 ...

  10. drf框架中分页组件

    drf框架中分页组件 普通分页(最常用) 自定制分页类 pagination.py from rest_framework.pagination import PageNumberPagination ...