AQS工作原理

AQS:AbstractQueuedSynchronizer,抽象队列同步器,用来构建锁和同步器。AQS相当于一个模版,而同步器则是AQS的具体应用。

AQS的发展

自旋锁:对一个变量执行CAS操作尝试获取锁。
——> 缺点:不能做到让权等待,可能出现饥饿问题,某个线程始终拿不到锁。

CLH锁:通过单向队列管理线程,而不是直接竞争共享变量。
——>缺点:大量自选操作浪费CPU资源。

AQS自旋+阻塞/唤醒,获取锁失败,先短暂自旋,如果还是失败,线程就进入阻塞状态。等待双向队列前面的线程释放锁,然后对后面的线程进行唤醒。

自定义同步器

  1. 自定义的同步器继承AbstractQueuedSynchronizer

  2. 重写AQS暴露的模版方法

    //独占方式。尝试获取资源,成功则返回true,失败则返回false。
    protected boolean tryAcquire(int)
    //独占方式。尝试释放资源,成功则返回true,失败则返回false。
    protected boolean tryRelease(int)
    //共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
    protected int tryAcquireShared(int)
    //共享方式。尝试释放资源,成功则返回true,失败则返回false。
    protected boolean tryReleaseShared(int)
    //该线程是否正在独占资源。只有用到condition才需要去实现它。
    protected boolean isHeldExclusively()
    

资源共享方式

Exclusive独占:只有一个线程能执行

Share共享:多个线程可同时执行

队列Node的状态含义

状态含义
cancelled1线程取消获取锁。线程在等待获取资源时被中断或超时。
init0加入队列的新节点的初始状态。
signal-1后继节点需要当前节点唤醒
condition-2节点在等待Condition。当其他线程调用了Condition的signal()方法时,节点会从等待队列转移到同步队列获取锁
propagate-3前继节点不仅会唤醒后继节点,同时会唤醒后继节点的后继节点

图解AQS工作原理

因为AQS只是一个模版,没有具体实现,故这里以ReentrantLock为例。

前提:有3个线程尝试获取锁。分别为T1、T2、T3

  1. T1获取到锁,T2会进入到等待队列中等待获取锁。在进入队列之前,需要对队列进行初始化。

    在这里插入图片描述

  2. T2尝试获取锁。但锁被T1获取,T2进入等待队列。同时将head节点的状态0更新为signal,表示需要对head节点的后继节点进行唤醒。

在这里插入图片描述

  1. T3尝试获取锁。但锁被T1获取,T3进入等待队列。同时将T2的状态0更新为signal,表示需要对T2节点的后继节点T3进行唤醒。

    在这里插入图片描述

  2. 此时T1释放锁,唤醒后继节点T2,。T2被唤醒后,会退出等待队列,但不是真正的退出,而是将T2节点变成head节点。

    在这里插入图片描述

  3. T2释放锁,唤醒后继节点T3。T3被唤醒后,退出等待队列,但不是真正的退出,而是将T3节点变成head节点。

在这里插入图片描述

本文的图源来自javaGuide

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值