JUC核心-AQS(AbstractQueuedSynchronizer)简析

AQS是什么?

  • AQS 全称是 AbstractQueuedSynchronizer, 它提供一种依赖于FIFO等待队列的构建锁和同步器的框架

  • CAS是什么?

CAS(Compare And Swap),即比较并交换。是解决多线程并行情况下使用锁造成性能损耗的一种机制,CAS操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,那么处理器会自动将该位置值更新为新值。否则,处理器不做任何操作。无论哪种情况,它都会在CAS指令之前返回该位置的值。CAS有效地说明了“我认为位置V应该包含值A;如果包含该值,则将B放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。

底层实现

整体结构

  • AQS 的结构大概可总结为以下 3 部分:

    • 用 volatile 修饰的整数类型的 state 状态,用于表示同步状态,提供 getState 和 setState, compareAndSetState来操作同步状态;
    • 提供了一个 FIFO 等待队列,实现线程间的竞争和等待,这是 AQS 的核心;其中, 链表头Head和链表尾Tail也有volatile修饰。
    • AQS 内部提供了各种基于 CAS 原子操作方法,如 compareAndSetState 方法,并且提供了锁操作的acquire和release方法。
  • 提供两种锁的默认实现方式:

    • 独占锁(Exclusive)
    • 共享锁(Shared)
  • tryAcquire, tryRelease 都是需要实现类自己去实现的方法, 如果不实现的话,是会抛出异常UnsupportedOperationException的

  • 用到的设计模式-模板模式, 在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。

独占锁

acquire获取独占锁

  • 伪代码实现
 while (!tryAcquire(arg)) {
    <em>enqueue thread if it is not already queued</em>;
    <em>possibly block current thread</em>;
 }
  • 代码实现
    • 先尝试获取锁,获取成功则成功
    • 尝试失败,则把当前线程包装成为一个节点,然后等待获取的机会
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}
  • NOTE这里有必要说明一下,就是当一个节点成为head节点的时候,他不一定会是下一个获取锁的节点,从上面代码也可以看出来,所以获取锁的线程都会先尝试获取锁一次,这样有可能等待队列的头节点也可能获取锁失败。

release释放独占锁

  • 伪代码实现
  if (tryRelease(arg))
     <em>unblock the first queued thread</em>;
  • 代码实现
public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

共享锁

acquireShared获取共享锁

  • 代码实现
public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}

releaseShared释放共享锁

  • 代码实现
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

FIFO队列

队列模型

这个在AQS的注释说明里边,Doug Lea已经说的很明确了,还做了图解

  • 这个等待队列是CLH(Craig, Landin, and Hagersten)队列的一个变种,这种队列常被用作自旋锁(这个概念就不展开了)
  • 作用:用于阻塞同步器
  • 结构
         +------+  prev +-----+       +-----+
 head    |      | <---- |     | <---- |     |  tail
         +------+       +-----+       +-----+
  • 入队:插入队尾
  • 出队:直接设置head即可

节点

  • 节点其实是把想要获取锁的线程包装了一番
//mode分exclusive和shared两种模式
new Node(Thread.currentThread(), mode);
  • 节点状态
/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED =  1;
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL    = -1;
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/**
 * waitStatus value to indicate the next acquireShared should
 * unconditionally propagate. 
 * 这个状态只在共享锁的模式下有效,这个传播的用处在哪儿呢?
 * 举例说明:读写锁,写读操作和写写操作互斥,读读之间不互斥;当调用acquireShared获取读
 * 锁时,会检查后续节点是否是获取读锁,如果是,则同样释放;
 */
static final int PROPAGATE = -3;

常见面试

  • 谈一下AQS吧 @可以从定义入手,然后讲
    • 不同锁状态的更改的实现方式
    • FIFO队列的实现方式
    • 核心技术CAS+volatile
  • CAS是什么?见上面的笔记
  • 为什么你说AQS的底层是CAS+volatile?
    • 表示锁状态的变量state,以及FIFO队列的头,尾,节点的状态都是volatile修饰的
    • 在设置state,队列的头,尾,状态的时候都有用到CAS技术
  • JUC包里的同步组件主要实现了AQS的哪些主要方法 ?
    • tryAcquire, tryRelease
    • tryAcquireShared, tryReleaseShared
    • isHeldExclusively
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,843评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,538评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,187评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,264评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,289评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,231评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,116评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,945评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,367评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,581评论 2 333
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,754评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,458评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,068评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,692评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,842评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,797评论 2 369
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,654评论 2 354

推荐阅读更多精彩内容