AQS是什么?

  AQS全称叫AbstractQueuedSynchronizer,顾名思义,抽象的队列同步装置,在java中是一个抽象类。java JUC包下常用的同步类都是通过继承AQS实现的,那么AQS到底是怎么实现的呢,

又为什么说AQS=volatile+CAS,我们通过分析ReentrantLock类的源码来一步步解开谜底。

  我们从初始化ReentrantLock开始

 /**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
} /**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

  可以看到ReentrantLock有两个构造方法,看带参数的注释可以知道如果传true,则是公平锁,这里我们使用无参构造,所以我们走的是上面一个构造方法。

所以我们调用的就是NonfairSync(非公平锁)的lock方法,如下图:

/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L; /**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
} protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}

首先来分析compareAndSetState方法到底干了啥,进入该方法;

protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

其实从名字上我们也可以看出这个是一个典型的CAS操作,看到unsafe就没必要往下看了,因为unsafe里面的方法被java设计者封装了,我们是看不了的。

可以看到这里是想对stateOffset这个属性进行CAS操作,找到stateOffset,发现最终指向的是state属性,

再找到state属性:

发现该属性是通过volatile修饰的一个int值,暂时我们还不知道这个属性有什么作用。再回到lock方法

假设我们是第一个线程第一次进行锁操作,那么这期间肯定没其他线程会去修改state的值,则肯定会更新成功,此时该方法返回true,并将state设置为1。

返回true之后就会执行setExclusiveOwnerThread方法,该方法表示将当前线程设置为独占访问。此时,第一个线程加锁的步骤就完了,然后就执行业务

代码,执行完再调用onlock方法解锁。当然这不是我们关注的重点,我们的重点是,当有第二个,第三个线程调用lock方法的时候,我们该怎么去保证同步。

继续回到代码,当第二给线程调用lock方法的时候,假设此时第一个线程还没有释放锁,那么一定会进入else的acquire方法:

先来看tryAcquire()这个方法,顾名思义,尝试去获得锁,tryAcquire实际调用的是nonfairTryAcquire() 方法,因为我们看的非公平锁。

代码如下:

这个方法比较简单,如果state等于0也就是没拿到锁,就用cas去尝试拿,拿到就返回true,如果

在当前线程中,如果说当前线程和锁的所有者是同一个线程,则把sate+1,表示锁的重入。

再来看acquireQueued(addWaiter(Node.EXCLUSIVE), arg),这个方法就不去细看了,大致 的意思

就是通过cas实现往队列里面放入等待的线程,当执行的线程释放锁的时候,该队列的线程会相互竞争

直到某一个线程拿到锁。

总结:

  1. 调用自定义同步器的tryAcquire()尝试直接去获取资源,如果成功则直接返回;
  2. 没成功,则addWaiter()将该线程加入等待队列的尾部,并标记为独占模式;
  3. acquireQueued()使线程在等待队列中休息,有机会时(轮到自己,会被unpark())会去尝试获取资源。获取到资源后才返回。如果在整个等待过程中被中断过,则返回true,否则返回false。
  4. 如果线程在等待过程中被中断过,它是不响应的。只是获取资源后才再进行自我中断selfInterrupt(),将中断补上。

由于此函数是重中之重,我再用流程图总结一下:

至此,acquire()的流程终于算是告一段落了。这也就是ReentrantLock.lock()的流程,不信你去看其lock()源码吧,整个函数就是一条acquire(1)!!!

参考:https://www.cnblogs.com/waterystone/p/4920797.html(如果需要详细的了解aqs的源码实现,请看这篇文章)

谈谈AQS的更多相关文章

  1. 美团Java面试154道题

    Java集合22题 ArrayList 和 Vector 的区别.ArrayList与Vector区别 说说 ArrayList,Vector, LinkedList 的存储性能和特性.ArrayLi ...

  2. 阿里Java架构师面试高频300题:集合+JVM+Redis+并发+算法+框架等

    前言 在过2个月即将进入9月了,然而面对今年的大环境而言,跳槽成功的难度比往年高了很多,很明显的感受就是:对于今年的java开发朋友跳槽面试,无论一面还是二面,都开始考验一个Java程序员的技术功底和 ...

  3. 350道面试题分享,拿下京东offer工资double

    350道面试题分享,拿下京东offer工资double 前言: 面试,其实是一个双向选择的过程,在这个过程里,我们不应该抱着畏惧的心态去对待,这样反而会影响自己的发挥.同时看中的应该不止薪资,还要看你 ...

  4. java 面试题目(java高级架构)

    题目信息 java基础: 1. Java 基础 JDK 和 JRE 有什么区别?   Java中JDK和JRE的区别是什么?它们的作用分别是什么? == 和 equals 的区别是什么? 两个对象的 ...

  5. 2020.4面试分享(7面收5个offer)

    都说金三银四是找工作的最佳时节,由于本人的个人职业规划跟目前工作内容不太相符(具体原因就不透露了,领导平时也要来这里逛,哈哈),四月份挑选了10多家公司投递简历(公司规模从几十人到上万人都有),参加了 ...

  6. 2020.4面试分享(7面收割5个offer)

    都说金三银四是找工作的最佳时节,由于本人的个人职业规划跟目前工作内容不太相符(具体原因就不透露了,领导平时也要来这里逛,哈哈),四月份挑选了10多家公司投递简历(公司规模从几十人到上万人都有),参加了 ...

  7. 美团 Java 面试 154 道题分享!

    Java集合22题 ArrayList 和 Vector 的区别. 说说 ArrayList,Vector, LinkedList 的存储性能和特性. 快速失败 (fail-fast) 和安全失败 ( ...

  8. Java面试,面试题

    Java面试,面试题 HashMap,HashTable,ConcurrentHash的共同点和区别 HashMap HashTable ConcurrentHashMap ArrayList和Lin ...

  9. 【面试普通人VS高手系列】谈谈你对AQS的理解

    AQS是AbstractQueuedSynchronizer的简称,是并发编程中比较核心的组件. 在很多大厂的面试中,面试官对于并发编程的考核要求相对较高,简单来说,如果你不懂并发编程,那么你很难通过 ...

随机推荐

  1. 用pChart生成雷达图图片

    需求 :由于工作需要,需要在一张背景图上添加这一张雷达图,之后图片可以在微信中长按保存.所以说我必须生成一张带有雷达图的图片第一反应是用百度echars雷达图做动态显示,之后截图.考虑到工作量和效率, ...

  2. 多测师讲解第一个月 _综合面试题_高级讲师肖sir

    第一个月综合面试题 1.  冒烟测试是什么意思?  对主要的用例测试 2.你们公司的项目流程是什么? 3.你们公司的bug分几个级别?  4个 4.你对外键是怎么理解的? 你会使用外键吗?给一个表添加 ...

  3. 超好用的UnixLinux 命令技巧 大神为你详细解读

    1.删除一个大文件 我在生产服务器上有一个很大的200GB的日志文件需要删除.我的rm和ls命令已经崩溃,我担心这是由于巨大的磁盘IO造成的,要删除这个大文件,输入: > /path/to/fi ...

  4. day28 Pyhton MRO和C3算法

    1.python多继承.一个类可以拥有多个父类 class ShenXian: # 神仙 def fei(self): print("神仙都会飞") class Monkey: # ...

  5. go正则

    package main import ( "fmt" "regexp" ) func main() { context1 := "3.14 1231 ...

  6. xshell多窗口同时执行输入命令

  7. zookeeper的管理功能

    一,查看当前zookeeper的版本 [liuhongdi@localhost ~]$ echo stat|nc 127.0.0.1 2181 Zookeeper version: 3.5.6-c11 ...

  8. ES概要

    ES分布式搜索,依赖了Lucene来提供搜索引擎功能,每个数据节点都是一个Lucene实例,通过将索引进行分片,写入和查询时候操作或查询对应分片,来达到水平扩展的能力 节点 Master node:负 ...

  9. uart与usart区别

    uart 通用异步收发传输器(Universal Asynchronous Receiver/Transmitter),通常称作UART,是一种异步收发传输器,是电脑硬件的一部分.它将要传输的资料在串 ...

  10. react-native 常见问题

    1.webpack使用babel-loader后编译报错 报错ERROR in ./entry.js Module build failed: SyntaxError: /Users/yixin/De ...