文章目录
AbstractQueuedSynchronizer源码
AbstractQueuedSynchronizer
通常简称AQS
,他是java.util.locks
包下的一个类,Java中的很多类都是通过改类实现的。
在本文中我们通过阅读源码的方式查看下其实现原理,使用的JDK版本为1.8.
1、类结构与数据结构
1.1 类继承关系
AbstractQueuedSynchronizer
继承AbstractOwnableSynchronizer
,AbstractOwnableSynchronizer
的定义是比较简单的,里面只有一个字段exclusiveOwnerThread
,该字段是用来存储当前占有同步器的的线程。
1.2 成员变量
AQS
类中的成员变量如下:
Node head
头节点Node tail
尾节点int state
状态值 通过对该字段的操作实现同步的逻辑
AQS
中有个ConditionObject
内部类,其成员变量如下
Node fitstWaiter
头节点Node lastWaiter
尾节点
1.3 数据结构
通过上面的成员变量,我们很容易想到这是一个链表结构,链表节点的定义如下:
static final class Node {
// 共享锁模式的nextWaiter
static final Node SHARED = new Node();
// 独占锁模式的nextWaiter
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() {
}
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) {
this.waitStatus = waitStatus;
this.thread = thread;
}
}
通过节点的定义我们发现里面双向链表和单向链表同时存在,这两个链表分别有什么用我们会在后面的源码学习中一点点的讲解。其结构如下图所示:
节点的状态有如下几种,我们会在后面的源码查看中了解什么时候会设置成相应的值:
- CANCELLED = 1
- SIGNAL = -1
- CONDITION = -2
- PROPAGATE = -3
- 0
2 获取/释放锁
在上面的部门我们了解了AQS
的数据结构,在这部分中我们看下AQS
是如何处理获取锁和释放锁的逻辑的。
AQS
中存在独占和共享两种模式,对外提供的获取/释放的方法如下:
protected final boolean compareAndSetState(int expect, int update)
通过CAS的方式修改state
属性public final void acquire(int arg)
获取排他锁public final void acquireShared(int arg)
获取共享锁public final boolean tryAcquireNanos(int arg, long nanosTimeout)
带超时时间的获取排他锁public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout)
带超时时间的获取共享锁public final boolean release(int arg)
释放排他锁public final boolean releaseShared(int arg)
释放共享锁
2.1 compareAndSetState方法
该方法是线程安全的修改state
属性的值,其使用的是Unsafe
类的CAS操作,其源码如下
protected final boolean compareAndSetState(int expect, int update) {
// 使用Unsafe类进行CAS操作,保证线程安全
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
2.2 acquire方法
该方法是排他锁获取锁的方法,其源码如下
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
// 获取锁失败且加入等待队列失败,执行Thread.interrupt()方法
selfInterrupt();
}
在这个方法中会调用tryAcquire
方法、addWaiter
方法和acquireQueued
方法。
tryAcquire
方法是尝试获得锁,阅读tryAcquire
方法的源码我们会发现在AQS
中直接抛出了异常,很明显这里使用了方法模板模式,需要子类来实现该方法,其源码如下:
protected boolean tryAcquire(int arg) {
// 在AQS中直接抛出异常,留给子类实现 模板方法
throw new UnsupportedOperationException();
}
如果获取锁失败,AQS
会将该线程添加到等待队列,addWaiter
方法源码如下
private Node addWaiter(Node mode) {
// 创建一个节点对象
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred