AQS,全名AbstractQueuedSynchronizer(抽象队列同步器),它是CLH(不明白的可以先了解一下CLH)的变种。它与CLH不同之处在于:
       CLH是一种公平锁,它是通过自旋同步队列中节点的前驱结点状态,判断同步队列中的节点是否能够进入临界区;AQS的同步队列中的节点不会以自旋的方式来进入临界区,而是先以公平或者不公平的方式尝试进入临界区,如果不能,则进行阻塞,等待被唤醒,再去尝试是否能够进入临界区。


AQS属于队列,那么就是一个一个节点连接而成,在AQS中节点的数据结构如下:

static final class Node {static final Node SHARED = new Node();/** 独占锁模式 */static final Node EXCLUSIVE = null;/*** AQS中判断节点是否为取消状态,有时候是判断状态值是否大于零*/static final int CANCELLED =  1;/** * 如果节点是这个状态,* 那么该节点就需要唤醒它的后继节点 */static final int SIGNAL    = -1;/*** 不明白,但是不影响对acquire方法的理解*/static final int CONDITION = -2;/*** 不明白,但是不影响对acquire方法的理解*/static final int PROPAGATE = -3;/** * 值为:-3 , -2 , -1 , 0 , 1 */volatile int waitStatus;volatile Node prev;volatile Node next;volatile Thread thread;Node nextWaiter;final boolean isShared() {return nextWaiter == SHARED;}final Node predecessor() throws NullPointerException {Node p = prev;if (p == null)throw new NullPointerException();elsereturn p;}Node() {}Node(Thread thread, Node mode) { this.nextWaiter = mode;this.thread = thread;}Node(Thread thread, int waitStatus) {this.waitStatus = waitStatus;this.thread = thread;}}

可以看出来AQS同步队列是一个双向链表结构。需要说明的是除了头节点是进入到临界区的节点,其他大部分节点(有一部分节点可能被取消了,waitStatus=1)都是希望进入临界区的节点。


acquire方法解析

AQS中的acquire方法,是获取独占锁方法,它的代码很简单,代码主体只有一个if判断语句:

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

可以看到acquire方法实现,主要是下面这三个方法

  1. tryAcquire(arg)
  2. addWaiter(Node.EXCLUSIVE)
  3. acquireQueued(addWaiter(Node.EXCLUSIVE), arg)

这三个方法的作用

  1. tryAcquire(arg)
    顾名思义,它就是尝试获取锁,AQS在这里没有对其进行功能的实现,只有一个抛出异常的语句,用户可以对其重写实现公平锁、不公平锁、可重入锁、不可重入锁
protected boolean tryAcquire(int arg) {throw new UnsupportedOperationException();
}
  1. addWaiter(Node.EXCLUSIVE)
    一旦尝试获取锁未成功,就要使用该方法将其加入同步队列尾部
private Node addWaiter(Node mode) {Node node = new Node(Thread.currentThread(), mode);// 快速尝试加入到同步队列队尾Node pred = tail;if (pred != null) {node.prev = pred;if (compareAndSetTail(pred, node)) {pred.next = node;return node;}}// 如果快速尝试没有成功,则自旋加入队尾,直到成功加入enq(node);return node;
}private Node enq(final Node node) {for (;;) {Node t = tail;if (t == null) { // Must initializeif (compareAndSetHead(new Node()))tail = head;} else {node.prev = t;if (compareAndSetTail(t, node)) {t.next = node;return t;}}}}

由于可能有多个线程并发加入队尾产生竞争,因此,采用compareAndSetTail无锁方法来保证同步

  1. acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
    一旦加入同步队列,就需要使用该方法,自旋阻塞唤醒来不断的尝试获取锁,直到被中断或获取到锁
final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;// 自旋for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // 帮助GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) /** 尝试获取锁失败是否阻塞线程获取锁 */ &&parkAndCheckInterrupt() /** 阻塞 */)interrupted = true;}} finally {if (failed)cancelAcquire(node);}
}

前面说过,当一个节点的前驱节点的waitStatus=SIGNAL,当其前驱结点释放锁的时候需要对其后继节点进行唤醒。shouldParkAfterFailedAcquire方法的功能就是判断该节点的前驱结点的waitStatus==SIGNAL,如果相等则该节点可以阻塞,否则将该节点的前驱结点waitStatus状态修改为SIGNAL。由此可以知道,该节点如果没有获取到锁,AQS就会尽最大努力(为什么说最大努力,而不是一定会将节点阻塞呢?可以思考一下,为什么,shouldParkAfterFailedAcquire里面能找到答案)将该节点阻塞,之后等待前驱结点唤醒,再尝试获取锁。

【java并发】AQS中acquire方法解析相关推荐

  1. JUC里面的相关分类|| java并发编程中,关于锁的实现方式有两种synchronized ,Lock || Lock——ReentrantLock||AQS(抽象队列同步器)

    JUC分类 java并发编程中,关于锁的实现方式有两种synchronized ,Lock AQS--AbstractQueuedSynchronizer

  2. 理解Java并发编程:volatile关键字解析

    文章目录 volatile关键字作用详解 原子/可见/有序 happen-before原则 volatile的作用 volatile的原理 volatile关键字作用详解 讲到Java中的volati ...

  3. Java并发编程中的若干核心技术,向高手进阶

    来源:http://www.jianshu.com/p/5f499f8212e7 引言 本文试图从一个更高的视角来总结Java语言中的并发编程内容,希望阅读完本文之后,可以收获一些内容,至少应该知道在 ...

  4. synchronized 异常_由浅入深,Java 并发编程中的 Synchronized

    synchronized 作用 synchronized 关键字是 Java 并发编程中线程同步的常用手段之一. 1.1 作用: 确保线程互斥的访问同步代,锁自动释放,多个线程操作同个代码块或函数必须 ...

  5. Java并发编程:volatile关键字解析(转载)

    转自https://www.cnblogs.com/dolphin0520/p/3920373.html Java并发编程:volatile关键字解析 Java并发编程:volatile关键字解析 v ...

  6. 由浅入深,逐步了解 Java 并发编程中的 Synchronized!

    作者 | sowhat1412  责编 | 张文 头图 | CSDN 下载自视觉中国 来源 | sowhat1412(ID:sowhat9094) synchronized 作用 synchroniz ...

  7. 转载:Java并发编程:volatile关键字解析

    看到一篇写的很细致的文章,感谢作者 作者:Matrix海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者Matrix海子和博客园共有,欢 ...

  8. java 线程由浅入深_由浅入深,Java 并发编程中的 Synchronized(一)

    synchronized 作用 synchronized 关键字是 Java 并发编程中线程同步的常用手段之一. 1.1 作用: 确保线程互斥的访问同步代,锁自动释放,多个线程操作同个代码块或函数必须 ...

  9. java empty isempty_Java中isEmpty方法如何使用?

    展开全部 isEmpty()方法有很多类都有,对于String类,62616964757a686964616fe4b893e5b19e31333264656134它是Java 6.0引入的, 当且仅当 ...

最新文章

  1. angular2集成highchart
  2. react-dnd 拖拽
  3. 走近webpack(3)--图片的处理
  4. 数据分析实战-PUBG数据集EDA
  5. Qt的Assistant制作自定义的软件帮助界面(记录)
  6. [导入]2007年美国电影上映时间表
  7. C++_虚函数的实现的基本原理
  8. jQueryWEUI自定义对话框-带有textarea
  9. 两个小球碰撞速度计算方法
  10. 每年都要调两次时间,美国人已经烦透了
  11. Pidgin 2.3.1语言设置方法
  12. [9i]多练扎马步,预防膝盖疼痛
  13. Jinja2安装与基本API用法
  14. Win11如何自动清理垃圾?Win11自动删除文件设置方法
  15. 医疗器械软件网络安全相关
  16. linux mock 使用
  17. SHT10型温湿度传感器工作时序分析及驱动程序与Proteus仿真的实现
  18. 实话实说 —— 心理模型vs实现模型
  19. linux安装宝塔面板命令大全
  20. 80GB医学影像数据集发布!OCTA-500公开下载

热门文章

  1. 用计算机弹追光使者,【B型】追光使者-洛天依(完整版歌词附)
  2. 钢铁产能年过剩超亿吨 发改委铁腕治“劣”
  3. VanillaNet:极简主义在深度学习中的力量
  4. 《炬丰科技-半导体工艺》 迈向硅衬底上的紫外光电系统
  5. 滴滴出行与上海交通大学共建联合实验室,加速产学研合作进程
  6. python数据挖掘商业案例_Python数据科学-技术详解与商业实践-第八讲作业
  7. 艾媒报告|2018-2019中国智慧物流行业研究报告
  8. 常州工学院c语言试题 选择题,常州工学院高等数学(上)综合测试题20.doc
  9. 阿里云超算战纪 | 凌云时刻
  10. 一种日志采集装置及方法