Java并发编程系列-AbstractQueuedSynchronizer

原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/10566625.html

一、概述

AbstractQueuedSynchronizer简称为AQS,是并发包中用于实现并发工具的基础类,非常明显,它是一个抽象类。

它提供了一个依赖于FIFO队列的框架用于实现各种阻塞锁与同步器。

它依赖于一个int值来表示状态,并定义了获取和修改该状态值的原子方法,具体的同步器需要实现该抽象类,并且使用它定义的这些原子方法来操作状态值。

它的实现类一般作为待实现的同步器的静态内部类而存在,用来提供一些方法来实现同步器的功能。

我们可以将其看作是基础的同步器,并不是具体的某一个同步器,而是同步器的一个抽象。

二、源码解析 2.1 继承体系解析

首先来看看其继承体系:

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

可以看到它继承了AbstractOwnableSynchronizer抽象类,这个类很简单,我们可以整体来看看:

// 就是一个简单的独占式同步器,持有被独占拥有的线程 public abstract class AbstractOwnableSynchronizer implements java.io.Serializable { private static final long serialVersionUID = 3737899427754241961L; // 供子类调用的构造器 protected AbstractOwnableSynchronizer() { } // 表示独占拥有的线程,下面是其get和set方法 private transient Thread exclusiveOwnerThread; protected final void setExclusiveOwnerThread(Thread thread) { exclusiveOwnerThread = thread; } protected final Thread getExclusiveOwnerThread() { return exclusiveOwnerThread; } } 2.2 内部类解析 2.2.1 Node

静态内部类Node用于将要加入同步队列的线程封装成为队列节点。这个队列采用双向链表实现,支持先进先出。

(1)修饰符: static final class Node {}

该静态内部类被final修饰,表明作者希望其不被继承修改。

(2)字段: static final class Node { // 两个节点标记,用于标识节点对应的线程获取锁的模式,是共享式获取,还是独享式获取 static final Node SHARED = new Node();// 共享模式的节点标记 static final Node EXCLUSIVE = null;// 独享模式的节点标记 // 四个节点状态,其实还有一个状态为0-表示当前节点在同步队列中,等待着获取锁 static final int CANCELLED = 1;// 表示当前节点封装的线程被中断或者超时 static final int SIGNAL = -1;// 表示当前节点的后继节点需要被唤醒(unpark) static final int CONDITION = -2;// 表示当前节点位于等待队列中,在等待条件满足 static final int PROPAGATE = -3;// 表示当前场景下后续的acquireShared能够得以执行?? // 节点状态,其值就是上面定义的这四个状态值再加上0 volatile int waitStatus; // 同步队列的节点指针 volatile Node prev;// 双向链表中节点指向前节点的指针 volatile Node next;// 双向链表中节点指向后节点的指针 // 节点封装的执行线程 volatile Thread thread; // 等待队列的节点指针 Node nextWaiter;// 单向链表中节点指向后节点的指针 }

节点状态:

0:默认状态,表示节点是同步队列中等待获取锁的线程的节点

1:CANCELLED,表示节点被取消,原因可能是超时或者被中断,一旦置于该状态,则不再改变

-1:SIGNAL,表示当前节点的后继节点被阻塞(或即将被阻塞)(使用park),因此当前线程释放锁或者被取消执行时需要唤醒(unpark)后继节点

-2:CONDITION,表示当前节点位于等待队列中,当节点被转移到同步队列的时候,状态值会被更新为0

-3:PROPAGATE,表示持续的传播releaseShared操作

(3)构造器: static final class Node { Node() {} Node(Thread thread, Node mode) { this.nextWaiter = mode; this.thread = thread; } Node(Thread thread, int waitStatus) { this.waitStatus = waitStatus; this.thread = thread; } }

三个构造器各有用处:

Node():用户初始化头结点,或者创建共享标记SHARED

Node(Thread thread, Node mode):给同步队列添加新节点时使用,用于构造新节点

Node(Thread thread, int waitStatus):给等待队列添加新节点时使用,用于构造新节点

注意:上面的构造器中的mode(模式)属于Node类型,它有两种模式SHARED和EXCLUSIVE,分别表示共享模式和独享模式。而waitStatus表示的是节点状态。

(4)方法: static final class Node { // 校验当前节点是否是共享模式 final boolean isShared() { return nextWaiter == SHARED; } // 获取前置节点,必须为非null final Node predecessor() throws NullPointerException { Node p = prev; if (p == null) throw new NullPointerException(); else return p; } }

方法解析:

isShared方法主要用于校验当前节点的锁获取模式,是共享还是独享,实现方式采用nextWaiter与SHARED比较,参照上面的第二个构造器的实现,我们可以知道在新增一个节点的时候,会对节点的nextWaiter进行赋值,而所赋的值正好是新增节点的模式标记,可以说nextWaiter持有节点的模式标记,那么拿其来与SHARED进行比较就是很显然的事情了。

predecessor方法用于获取前置节点,主要是在当前置节点不可为null时使用,这样当前置节点为null,就会抛出空指针。

2.2.2 Condition

Condition并非AQS中的内部类,而是其内部类ConditionObject的父接口,为了后面的ConditionObject,我们提前了解下Condition。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwysj.html