02_AbstactQueuedSynchronizer之AQS

先总字节跳动及其它大厂面试题说起

  1. ReentantLock实现原理,简单说一下AQS?
  2. synchronized的锁优化过程,详细说一下吧,偏向锁和轻量级锁有什么区别?

前置知识

公平锁和非公平锁

可重入锁

LockSupport

自旋锁

数据结构之链表

设计模式之模板设计模式

是什么

字面意思

抽象的队列同步器

源代码

public abstract class AbstractQueuedSynchronizer
    extends AbstractOwnableSynchronizer
    implements java.io.Serializable {

在这里插入图片描述

技术解释

是用来构建锁或者其他同步器组件的重量级基础框架及整个JUC体系的基石,通过内置的FIFO队列来完成资源获取,线程的排队工作,并通过一个int类型变量表示持有锁的状态。
在这里插入图片描述
CLH:Craig、Landin 和 Hagersten队列,是一个单向链表,AQS中的队列是CLH变体的虚拟双向队列FIFO.

AQS为什么是JUC内容中最重要的基石

和AQS有关的类

  • ReentrantLock
  • CountDownLatch
  • ReentrantReadWriteLock
  • Semaphore
  • ……
    在这里插入图片描述
    通过查看几个累的源代码可以看出底层都封装一个AbstactQueuedSynchronizer;所以这个类是JUC的基石。

进一步理解锁和同步器的关系

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

同步器:面向锁的实现者,比如Java并发大神DougLee,提出统一规范并简化了锁的实现,屏蔽了同步状态管理、阻塞线程排队和通知、唤醒机制等。

能干嘛

加锁会导致阻塞,有阻塞就需要排队,实现排队必然需要有某种形式的队列来进行管理

解释说明:

抢到资源的线程直接使用处理业务逻辑,抢不到资源的必然涉及一种排队等候机制。抢占资源失败的线程继续去等待(类似银行业务办理窗口都满了,暂时没有受理窗口的顾客只能去候客区排队等候),但等候线程仍然保留获取锁的可能且获取锁流程仍在继续(候客区的顾客也在等着叫号,轮到了再取受理窗口办理业务)。

既然说到了队列等候机制,那么就一定会有某种队列形成,这样的队列是什么数据结构呢?

如果共享资源占用,就需要一定的阻塞等待唤醒机制来保证锁分配。这个机制主要用的是CLH队列的变体实现的,将暂时获取不到锁的线程加入到队列中,这队列就是AQS的抽象表现。他将请求共享资源的线程封装成队列的节点(Node),通过CAS、自旋以及LockSupport.park()的方式,维护state变量的状态,使并发达到同步的控制效果。

在这里插入图片描述

AQS初步

AQS初识

官网解释
在这里插入图片描述
有阻塞就需要排队,实现排队必然需要队列

AQS使用一个volatile的int类型的成员变量来表示同步状态,通过内置的FIFO队列来完成资源获取的排队工作,将每条要去抢占资源的线程封装成一个Node节点来实现锁的分配,通过CAS完成对State值的修改。

static final class Node {
    volatile Node prev;  //上一个节点指针
    volatile Node next;  //下一个节点指针
    volatile Thread thread;//封装的等待线程
    .....
}
//队列的头部指针
private transient volatile Node head;
//队列的尾部指针
private transient volatile Node tail;
//同步的状态变量
private volatile int state;

在这里插入图片描述

AQS内部体系架构

AQS自身
AQS的int变量

AQS的同步状态state成员变量,private volatile int state;

银行办理业务的受理窗口状态,零就是没有人,自由状态可以办理;大于等于1,有人占用窗口,等着取号

AQS的CLH队列

在这里插入图片描述

小总结

有阻塞就需要排队,实现排队必然需要队列

state变量+CLH变种的双端队列

内部类Node

Node的int变量: Node的等待状态waitStatus成员变量:volatile int waitStatus;

等候区其他顾客(其他线程)的等待状态,队列中每个排队的个体就是一个Node

AQS同步队列的基本结构

static final class Node {
    /** 共享模式 Marker to indicate a node is waiting in shared mode */
    static final Node SHARED = new Node();
    /** 独占模式 Marker to indicate a node is waiting in exclusive mode */
    static final Node EXCLUSIVE = null;
    /** 线程被取消了 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;
    /** 等待condition唤醒 waitStatus value to indicate thread is waiting on condition */
    static final int CONDITION = -2;
    /**
     * waitStatus value to indicate the next acquireShared should
     * unconditionally propagate
     * 共享式同步状态获取将会无条件地传播下去
     */
    static final int PROPAGATE = -3;
    //初始为0,状态是上面的几种
    volatile int waitStatus;
    //前指针
    volatile Node prev;
    //后指针
    volatile Node next;
    //等待线程
    volatile Thread thread;
    //........
}

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

从我们的ReentrantLock开始解读AQS

见下一章笔记。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值