Java 抽象同步队列 AbstractQueuedSynchronizer

目录

1. AbstractQueuedSynchronizer 介绍

2. AQS 内部结构

3. 状态信息 state

4. 内部类 Node

4.1 Node 类源码

4.2 对 Node 的 CAS 操作

4.3 队列中的 Node 操作

5. 内部类 ConditionObject

5.1 await() 方法

5.2 signal() 方法

扫描二维码关注公众号,回复: 10923292 查看本文章

6. 获取和释放资源的方法

6.1 独享方式

6.2 共享方式


1. AbstractQueuedSynchronizer 介绍

抽象同步队列 AbstractQueuedSynchronizer ,简称 AQS,它是实现阻塞锁和其他基于先入先出(FIFO)等待队列的同步组件。

并发包中锁的底层实现(如 ReentrantLock )的底层实现就是使用 AQS 实现的。

2. AQS 内部结构

i. AQS 继承自 AbstractOwnableSynchronizer

ii. 类 ConditionObject 主要提供一种条件,由子类决定是否支持独占模式

iii. 类 Node,作为先入先出(FIFO)阻塞队列里面的每个节点

3. 状态信息 state

AQS 维持了一个单一的状态信息 state,可通过 getState()、setState(int newState)、compareAndSetState(int expect, int update) 方法来修改 state 的值。

private static final Unsafe unsafe = Unsafe.getUnsafe();
// 状态信息
private volatile int state;
// 返回当前的状态值。该操作拥有 volatile 读的内存语义
protected final int getState() {
    return state;
}
//设置状态值
protected final void setState(int newState) {
    state = newState;
}
// 通过 unsafe 类原子的设置同步状态值为给定的 update 值,设置成功后返回true,否则返回false
protected final boolean compareAndSetState(int expect, int update) {
    return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

state 作用举例:

ReentrantLock 中,state 表示当前线程获取锁的可重入次数。

ReentrantReadWriteLock 中,state 高 16 位表示获取读锁的次数,低 16 为表示获取写锁的线程的可重入次数。

4. 内部类 Node

4.1 Node 类源码

static final class Node {
    // 标记符,共享模式下的等待节点
    static final Node SHARED = new Node();
    // 标记符,独占模式下等待节点
    static final Node EXCLUSIVE = null;
    
    /**
      * 等待状态值
      *   1 表示线程已经被取消
      * -1 表示一个后继节点的线程需要唤醒
      * -2 表示线程等待在某种条件下
      * -3 表示下一次共享式获取状态的操作应该无条件的传播
      */
    static final int CANCELLED =  1;
    static final int SIGNAL    = -1;
    static final int CONDITION = -2;
    static final int PROPAGATE = -3;

   // 状态字段,取上述 4 个状态值。值为 0,表示非以上状态
    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() { 
    }
    // addWaiter 使用。给线程添加等待模型
    Node(Thread thread, Node mode) {
        this.nextWaiter = mode;
        this.thread = thread;
    }
    // Condition 使用,给线程添加等待条件
    Node(Thread thread, int waitStatus) {
        this.waitStatus = waitStatus;
        this.thread = thread;
    }
}

4.2 对 Node 的 CAS 操作

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long stateOffset;
private static final long headOffset;
private static final long tailOffset;
private static final long waitStatusOffset;
private static final long nextOffset;

static {
    try {
        stateOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
        headOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("head"));
        tailOffset = unsafe.objectFieldOffset
            (AbstractQueuedSynchronizer.class.getDeclaredField("tail"));
        waitStatusOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("waitStatus"));
        nextOffset = unsafe.objectFieldOffset
            (Node.class.getDeclaredField("next"));

    } catch (Exception ex) { throw new Error(ex); }
}

/**
 * 使用 unsafe 类对 Node 进行原子更新。如果当前状态值等于预期值,则以原子方式将同步状态设置为给定的更新值。
 */
private final boolean compareAndSetHead(Node update) {
    return unsafe.compareAndSwapObject(this, headOffset, null, update);
}

private final boolean compareAndSetTail(Node expect, Node update) {
    return unsafe.compareAndSwapObject(this, tailOffset, expect, update);
}
private static final boolean compareAndSetWaitStatus(Node node,
                                                        int expect,
                                                        int update) {
    return unsafe.compareAndSwapInt(node, waitStatusOffset,
                                    expect, update);
}
private static final boolean compareAndSetNext(Node node,
                                                Node expect,
                                                Node update) {
    return unsafe.compareAndSwapObject(node, nextOffset, expect, update);
}

4.3 队列中的 Node 操作

/**
* 将节点加入队列,必要时进行初始化
*/
private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) {
            // 尾结点为空,需要初始化
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            // 尾结点不为空,unsafe进行插入节点
            node.prev = t;
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}
/**
 * 为当前线程设置指定模式。并加入队列
 */
private Node addWaiter(Node mode) {
    Node node = new Node(Thread.currentThread(), mode);
    Node pred = tail;
    if (pred != null) {
        node.prev = pred;
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}
/**
 * 设置头结点
 */
private void setHead(Node node) {
    head = node;
    node.thread = null;
    node.prev = null;
}
/**
 * 如果存在后继节点则进行唤醒操作
 */
private void unparkSuccessor(Node node) {
    int ws = node.waitStatus;
    if (ws < 0)
        compareAndSetWaitStatus(node, ws, 0);
    Node s = node.next;
    if (s == null || s.waitStatus > 0) {
        s = null;
        for (Node t = tail; t != null && t != node; t = t.prev)
            if (t.waitStatus <= 0)
                s = t;
    }
    if (s != null)
        LockSupport.unpark(s.thread);
}

5. 内部类 ConditionObject

ConditionObject 实现了 Condition 接口。Condition 对象是由 Lock 对象创建的。

/** 
 * 等待队列中的头结点
 */
private transient Node firstWaiter;
/** 
 * 等待队列中的尾结点
 */
private transient Node lastWaiter;

ConditionObject 核心的两个方法:await() 、signal()

5.1 await() 方法

  • 当前线程进入等待状态,知道被通知(signal)或中断
  • 当前线程将进入运行状态且从 await() 方法返回的情况:
    • 其他线程调用该 Condition 的 signal() 或 signalAll() 方法
    • 其他线程调用 interrupt() 方法中断当前线程
    • 如果等待线程从 await() 方法返回,则该线程已经获取了 Condition 对象所对应的锁

5.2 signal() 方法

唤醒一个等待在 Condition 上的线程,该线程从等待方法返回前必须获得与 Condition 相关联的锁

signal() 为唤醒一个线程,signalAll() 为唤醒所有等待的线程

6. 获取和释放资源的方法

独享方式:acquire(int arg)、acquireInterruptibly(int arg)、release(int arg)

共享方式:acquireShared(int arg) 、acquireSharedInterruptibly(int arg)、releaseShared(int arg) 

6.1 独享方式

/**
 * 获取独享锁
 * tryAcquire 需要子类重写方法
 */
public final void acquire(int arg) {
        // 尝试获取锁,获取成功返回 true,否则返回 false
    if (!tryAcquire(arg) &&  
        // 没有获取则加入队列尾部,并通过 LockSupport.park(this)挂起自己
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) 
        // 进行自我中断
        selfInterrupt(); 
}
// 线程自我中断
static void selfInterrupt() {
    Thread.currentThread().interrupt();
}
/**
 * 试着释放当前线程持有的独占锁并唤醒后继节点
 */
public final boolean release(int arg) {
    // tryRelease 独享式释放同步状态,需要子类重写
    if (tryRelease(arg)) { 
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}
/**
 * 获取独占锁的可中断模式
 */
public final void acquireInterruptibly(int arg)
            throws InterruptedException {
    if (Thread.interrupted())
        // 当前线程如果中断,则抛出中断异常
        throw new InterruptedException();
    if (!tryAcquire(arg)) // 尝试获取锁
        // 获取锁失败,则调用 doAcquireInterruptibly 获取独享锁的可中断模式
        doAcquireInterruptibly(arg);
}

6.2 共享方式

共享方式与独享方式类似

public final void acquireShared(int arg) {
    if (tryAcquireShared(arg) < 0)
        // 获取共享锁的不中断模式
        doAcquireShared(arg);
}
public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    if (tryAcquireShared(arg) < 0)
        doAcquireSharedInterruptibly(arg);
}
public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
发布了7 篇原创文章 · 获赞 3 · 访问量 308

猜你喜欢

转载自blog.csdn.net/sl285720967/article/details/105588703
今日推荐