java并发包提供的同步工具和线程池,底层是基于什么原理来设计和实现的呢?这个非常重要。

我是李福春,我在准备面试,今天的题目是:

CAS和AQS是什么?

答:CAS是一系列的操作集合,获取当前值进行计算,如果当前值没有改变,表示线程没有被占用,直接更新成功,否则,进行重试或者返回成功或者失败。 他是java并发工具包中lock-free的基础吗,依赖底层的cpu提供的特定指令实现。底层依赖于Unsafe的本地对象来实现。

AQS: 全称是AbstractQueuedSynchronizier,抽象队列同步器;他是各种同步工具锁的基础,比如ReentrantLock, CyclicBairier都是基于AQS来实现的。

CAS

以AtomicInteger为例子来分析一下CAS的应用。


首先看内部结构:

然后分析一下他的一个利用CAS实现的原子操作。
```java
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
return v;
}
```
这是一个自旋操作,利用Unsafe比较内存的偏移量,基于cpu指令保证修改的原子可见性。

使用CAS也是有缺点的:
1,自旋次数是假定冲突情况很少的理想情况,但是情况不理想容易过度消耗CPU;
2, ABA问题,一般使用加版本号的 AtomicStampedRefence来搞定;

在实际的工作中如何使用CAS来保证同步操作呢?

可以基于AtomicFieldLongUpdater来实现。比如下面是一个基于CAS实现的同步更新数据库索引的例子,代码如下:

 public static class AtomicBTreePartition{

        private volatile long lock;

        private static final AtomicLongFieldUpdater<AtomicBTreePartition>
lockFieldUpdater
=AtomicLongFieldUpdater
.newUpdater(AtomicBTreePartition.class,"lock"); public void acquireLock(){ long t = Thread.currentThread().getId(); while (!lockFieldUpdater.compareAndSet(this, 0, 1)){
//数据库操作
}
} public void releaseLock(){ } }

AQS

她的组成核心主要有3个部分。

下面以ReentrantLock的非公平锁为例,分析一下它的加锁和释放锁的实现。
加锁操作代码:

  public void lock() {
sync.acquire(1);
}

继续跟进:

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

非公平锁的获取锁操作:

final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();// 获取当前AQS内部状态量
if (c == 0) {
// 0表示无人占有,则直接用CAS修改状态位,
if (compareAndSetState(0, acquires)) {
// 不检查排队情况,直接争抢
setExclusiveOwnerThread(current);
//并设置当前线程独占锁
return true;
}
} else if (current == getExclusiveOwnerThread()) {
//即使状态不是0,也可能当前线程是锁持有者,因为这是再入锁
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}

排队竞争:

final boolean acquireQueued(final Node node, int arg) {
boolean interrupted = false;
try {
for (;;) {// 循环
final Node p = node.predecessor();// 获取前一个节点
if (p == head && tryAcquire(arg)) {
// 如果前一个节点是头结点,表示当前节点合适去tryAcquire
setHead(node); // acquire成功,则设置新的头节点
p.next = null; // 将前面节点对当前节点的引用清空
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node))
// 检查是否失败后需要park
interrupted |= parkAndCheckInterrupt();
}
} catch (Throwable t) {
cancelAcquire(node);// 出现异常,取消
if (interrupted)
selfInterrupt();
throw t;
}

小结

本节介绍了CAS和AQS的概念,然后以AtomicInteger为例切入原子操作是怎么利用CAS来保证的。
最后,以ReentrantLock的加锁操作,跟进了是如何利用AQS来保证内部的不同操作的。


算是初步探究了同步的实现原理。





原创不易,转载请注明出处。

面试刷题22:CAS和AQS是什么?的更多相关文章

  1. 安利一个基于Spring Cloud 的面试刷题系统。面试、毕设、项目经验一网打尽

    推荐: 接近100K star 的Java学习/面试指南 Github 95k+点赞的Java面试/学习手册.pdf 今天给小伙伴们推荐一个朋友开源的面试刷题系统. 这篇文章我会从系统架构设计层面详解 ...

  2. 相似的RGB颜色——算法面试刷题3(for google),考察二分

    在本题中,每个大写字母代表从“0”到“f”的一些十六进制数字. 红绿蓝三元色#AABBCC可以简写为#ABC. 例如,#15c是颜色#1155cc的简写. 现在,假设两种颜色#ABCDEF和#UVWX ...

  3. 有效的括号序列——算法面试刷题4(for google),考察stack

    给定一个字符串所表示的括号序列,包含以下字符: '(', ')', '{', '}', '[' and ']', 判定是否是有效的括号序列. 括号必须依照 "()" 顺序表示, & ...

  4. 回文的范围——算法面试刷题2(for google),考察前缀和

    如果一个正整数的十进制表示(没有前导零)是一个回文字符串(一个前后读取相同的字符串),那么它就是回文.例如,数字5, 77, 363, 4884, 11111, 12121和349943都是回文. 如 ...

  5. 有效单词词广场——算法面试刷题5(for google),考察数学

    给定一个单词序列,检查它是否构成一个有效单词广场.一个有效的单词广场应满足以下条件:对于满足0≤k<max(numRows numColumns)的k,第k行和第k列对应的字符串应该相同,. 给 ...

  6. AI面试刷题版

    (1)代码题(leetcode类型),主要考察数据结构和基础算法,以及代码基本功 虽然这部分跟机器学习,深度学习关系不大,但也是面试的重中之重.基本每家公司的面试都问了大量的算法题和代码题,即使是商汤 ...

  7. 刷题22. Generate Parentheses

    一.题目说明 这个题目是22. Generate Parentheses,简单来说,输入一个数字n,输出n对匹配的小括号. 简单考虑了一下,n=0,输出"";n=1,输出" ...

  8. 面试刷题11:java系统中io的分类有哪些?

    随着分布式技术的普及和海量数据的增长,io的能力越来越重要,java提供的io模块提供了足够的扩展性来适应. 我是李福春,我在准备面试,今天的问题是: java中的io有哪几种? java中的io分3 ...

  9. 面试刷题12:zero copy是怎么回事?

    文件copy是java的io部分不可忽视的内容. 我是李福春,我在准备面试,今天的问题是: zero-copy是怎么回事? 操作系统的空间划分为内核态空间, 用户态空间: 内核态空间相对操作系统具备更 ...

随机推荐

  1. create view and switch view

    pageView扩展backbone cAbstractApp定义view加载.切换.回退.跳转-webApp/cWebViewApp/hybirdApp为其子类 1.cWebApp扩展了父类的bin ...

  2. 查看python库文档

    安装完python第三方库以后,经常需要查询其文档,其实python就自带文档查看器.可以查看所有内置库和第三方库的文档,虽然不是很详尽,但是总比没有的好. 在命令行窗口 python -m pydo ...

  3. 54-with管理文件操作上下文

    目录 with管理文件操作上下文 with管理文件操作上下文 之前我们使用open()方法操作文件,但是open打开文件后我们还需要手动释放文件对操作系统的占用.其实我们可以更方便的打开文件,即Pyt ...

  4. psql的时间类型,通过时间查询

    psql的时间类型,通过时间查询 psql有date/timestamp类型,date只显示年月日1999-01-08,而timestamp显示年月日时分秒 1999-01-08 09:54:03.2 ...

  5. 《即时消息技术剖析与实战》学习笔记11——IM系统如何保证服务高可用:流量控制和熔断机制

    IM 系统的不可用主要有以下两个原因: 一是无法预测突发流量,即使进行了服务拆分.自动扩容,但流量增长过快时,服务已经不可用了: 二是业务中依赖的这些接口.资源不可用或变慢时,比如发消息可能需要依赖& ...

  6. RabbitMQ面试题集锦(精选)(另附思维导图)

    1.使用RabbitMQ有什么好处? 1.解耦,系统A在代码中直接调用系统B和系统C的代码,如果将来D系统接入,系统A还需要修改代码,过于麻烦! 2.异步,将消息写入消息队列,非必要的业务逻辑以异步的 ...

  7. python虚拟环境安装使用

    # 安装 pip install virtualenv pip install virtualenvwrapper-win # win环境下 liunx下不需要-win #创建一个文件夹并cd进去mk ...

  8. iframe 框架父页面刷新子页面

    1.父页面添加: <script> function testBtn(){   var reshSrc = document.getElementById('myFrame').src; ...

  9. python3使用js2py

    安装: pip install js2py 使用: 执行js函数: 执行js函数: import js2py js = js2py.EvalJs({}) js.execute("" ...

  10. 个人项目(Word Count)

    一.Github项目地址 https://github.com/AllForward/GP_Homework/tree/master/个人项目 二.题目叙述 这个项目要求写一个命令行程序,模仿已有wc ...