AQS队列同步器详解

AbstractQueuedSynchronizer

相关类图如:AQS类图所示

image-20221205220946918

AQS类图

AbstractQueuedSynchronizer是用来实现锁或者其他同步器组件的公共基础部分的抽象实现。是重量级基础框架及整个JUC体系的基石,主要用于解决锁分配给谁的问题。整体就是一个抽象的FIFO队列来完成资源获取线程的排队工作,并通过int变量表示持有锁的状态

CLH队列,全程Craig、Landin and Hagersten队列,是一个单向链表,AQS中的队列是CLH的一种变体的虚拟双向FIFO队列。逻辑示意图如图:虚拟FIFO双向队列示意图所示

在这里插入图片描述

虚拟FIFO双向队列示意图

大部分我们使用并发组件基本上都和AQS有关,例如CountDownLatch,ReentranLock之类得


锁和同步器的关系

锁:面向锁的使用者,定义了程序员和锁交互的使用层API,隐藏了实现细节,调用即可

同步器:面向锁的实现者,统一规范并简化了锁的实现,将其抽象出来,屏蔽了同步状态管理同步队列的管理和维护,阻塞线程排队和通知、唤醒机制等,是一切锁和同步组件实现的——公共基础部分


AQS内部静态类Node的相关介绍
static final class Node {
   
	//共享锁方式
    static final Node SHARED = new Node();
	
    //独占锁方式
    static final Node EXCLUSIVE = null;

    //线程被取消
    static final int CANCELLED =  1;

    //后继线程需要唤醒
    static final int SIGNAL    = -1;

    //等待condition唤醒
    static final int CONDITION = -2;

    //共享式同步状态获取将会无条件传播下去
    static final int PROPAGATE = -3;

    //初始化状态0,状态值是上面的几种
    volatile int waitStatus;

    //前驱节点
    volatile Node prev;

    //后继节点
    volatile Node next;

    //封装到Node中的线程
    volatile Thread thread;
}

等待状态相关属性说明如下

waitStatus 含义
0 当一个Node节点初始化时的状态的默认值
CANCELLED:1 表示线程获取锁的请求已经取消
CONDITION:-2 表示节点在等待队列中,节点线程等待唤醒
PROPAGATE:-3 当前线程处于SHARED情况下,该字段才会使用
SIGNAL:-1 表示线程已经准备好了,就等资源释放

等待锁方式状态说明如下

模式 含义
SHARED 表示线程以共享的模式等待锁
EXCLUSIVE 表示线程以独占的模式等待锁

AQS源码分析

以ReentrantLock中的非公平锁为例,相关类图如:ReentrantLock相关类图所示

image-20221207214309169
ReentrantLock相关类图
ReentrantLock非公平锁加锁源码解读
private final ReentrantLock lock=new ReentrantLock();

//实例化一个非公平锁,将其引用赋值给ReentrantLock的内部类Sync类型的sync成员变量
public ReentrantLock() {
   
    sync = new NonfairSync();
}

//执行加锁操作
lock.lock();

public void lock() {
   
    /**调用成员变量的acquire方法,
    因为内部类继承了AbstractQueuedSynchronizer类并且没有重写acquire方法所以实际上还是调的父类的方法**/
    sync.acquire(1);
}

//AQS中的acquire方法
public final void acquire(int arg) {
   
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

现在单独来解析AQS方法中加锁调用的三个方法 tryAcquire,acquireQueued,addWaiter

tryAcquire方法

该方法位于AQS中,是一个钩子方法,我们直到AQS实际上是使用的模板方法设计模式,所以通常会留下钩子方法以供子类去实现

//调用了AQS中的tryAcquire,这是一个钩子方法,留给子类去实现的,具体的操作结果应该是由子类来做的
protected boolean tryAcquire(int arg) {
    
throw new UnsupportedOperationException();
}

通过架构图可以知道,ReentrantLock的静态内部类Sync继承了AQS,而非公平锁的加锁又是由ReentrantLock的静态内部类NonfairSync来实现的,该类又是继承的ReentrantLock静态内部类Sync的,所以,本质上来说,实现AQS的tryAcquire方法是由ReentrantLock的静态内部类NonfairSync实现的。该方法主要就是进行抢锁操作,判断如果AQS中的锁状态标志位位0则,表示没有线程占用锁CAS操作设置锁的状态位为1,并且以独占的方式获取到锁。如果锁状态标志位不为0,那么就判断,获取到锁的线程是不是自己,如果是则CAS操作将AQS中的锁状态标记位加1表示当前线程获取到锁的次数。否则的话就是抢占失败返回false

/**
ReentrantLock类中的静态内部类NonfairSync,
继承了ReentrantLock的静态内部类Sync,
Sync又是继承的AQS,
所以AQS中的钩子方法就是由孙子类NonfairSync来进行实现了
**/
protected final boolean tryAcquire
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值