队列同步器AQS的实现与分析——概述

AQS(AbstractQueuedSynchronizer)

上一期,我们介绍了乐观锁,而乐观锁的本质即是CAS,操作系统提供了支持CAS修改内存值的原子指令,所以乐观锁得以实现。从软件工程的角度去看,虽然底层已经通过CAS实现了乐观锁,Java的底层已经在Unsafe这个类中封装了compareAndSwap方法,支持了对CAS原语的调用,为了使上层更加易用,需要经过进一步的抽象和封装。抽象这个词虽然简单,但私以为要做出高内聚低耦合的抽象绝对是难点。在Java中最著名的并发包就是JUC,其中的组件和日常Java开发息息相关。

在JUC中,最核心的组件便是AQS。可以这么理解,AQS是对CAS的一种封装和丰富,AQS引入了独占锁、共享锁等性质。基于AQS,JUC中提供了更多适用于各种预设场景的组件,当然你也可以基于AQS开发符合自身业务场景的组件。所以,AQS作为承下启上的重点,我们需要仔细来看。

队列同步器AQS是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。
在这里插入图片描述

1、AQS成员属性:

private volatile int state;

state就是用于判断共享资源是否正在被占用的标记位。

为什么是int类型而不是boolean类型呢?
这是由于AQS是支持独占和共享两种加锁模式的,那么在共享模式下,state可以用来记录线程占用的数量。

private transient volatile Node head;

private transient volatile Node tail;

AQS中存在一个队列用于对等待线程进行管理,这个队列通过一个FIFO的双向链表来实现。head 和 tail 变量表示这个队列的头尾。

FIFO双向链表:
在这里插入图片描述

2、AQS内部类:

队列中每个节点的类型就是内部类Node

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;
        
      static final int CANCELLED =  1;

      static final int SIGNAL    = -1;

      static final int CONDITION = -2;

      static final int PROPAGATE = -3;
        
      volatile int waitStatus;
        
      volatile Node prev;

      volatile Node next;

      volatile Thread thread;

      Node nextWaiter;

      final boolean isShared() {
          return nextWaiter == SHARED;
      }

      final Node predecessor() throws NullPointerException {
          Node p = prev;
          if (p == null)
              throw new NullPointerException();
          else
              return p;
      }

      Node() {    // Used to establish initial head or SHARED marker
      }

      Node(Thread thread, Node mode) {     // Used by addWaiter
          this.nextWaiter = mode;
          this.thread = thread;
      }

      Node(Thread thread, int waitStatus) { // Used by Condition
          this.waitStatus = waitStatus;
          this.thread = thread;
      }
}

Node中主要存储了线程对象(thread)、节点在队列里的等待状态(waitStatus)、前后指针
(prev、next)等信息。这里需要重点关注的是waitStatus这个属性,它是一个枚举值,AQS工作时必然伴随着Node的waitStatus值的变化,如果理解了waitStatus变化的时机,那对理解AQS整个工作原理有很大的帮助。

waitStatus主要包含四个状态:
▲0,节点初始化默认值或节点已经释放锁
▲CANCELLED为1,表示当前节点获取锁的请求已经被取消了
▲SIGNAL为-1,表示当前节点的后续节点需要被被唤醒
▲CONDITION为-2,表示当前节点正在等待某一个Condition对象,和条件模式相关
▲PROPAGATE为-3,传递共享模式下锁释放状态,和共享模式相关

3、共享资源的两种方式

独占模式
共享模式

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小小本科生debug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值