AQS 学习

201 阅读3分钟

数据结构

AQS涉及数据结构

static final class Node {
	// 共享节点-- 读写锁中读锁
	static final Node SHARED = new Node();
	// 独占节点
    static final Node EXCLUSIVE = null;
	// 队列中节点的状态 0/SIGNAL 存在AQS队列;CONDITION 存在Condition 队列
	volatile int waitStatus;
    // 双链表前驱
	volatile Node prev;
    // 双链表后继
    volatile Node next;
    // 单链表下一节点
    Node nextWaiter;
    ...
}

public abstract class AbstractQueuedSynchronizer{
	// AQS 队列头节点
	private transient volatile Node head;
    // AQS 队列尾节点
    private transient volatile Node tail;
    // 同步状态
    // ReentrantLock 0- 无锁,1-有锁,>1 重入锁
    private volatile int state;
    ...
}

public class ConditionObject implements Condition, java.io.Serializable {
  // condition 队列头节点
  private transient Node firstWaiter;
  // condition 队列未节点
  private transient Node lastWaiter;
}

注意

  • AQS 队列是一个双向链表
  • Condition队列是一个单向链表
  • t.waitStatus = Node.CONDITION 标识节点在Condition队列
  • t.waitStatus=0/Node.SIGNAL 标识节点在AQS队列

ReentrantLock 源码分析

锁的实现(设计思维--互斥锁)

  • 锁的互斥特性 -> 共享资源 -> 标记位(0--无锁,1--有锁)
  • 没有抢到锁的线程?->释放CPU 资源(等待 -> 唤醒)
  • 等待线程如何存储? -> 数据结构去存储一些等待中的线程,FIFO(等待线程)
  • 公平非公平(能否插队)
  • 重入的特性(是否是一个人?ThreadId)

技术方案

  • volatile state 0-无锁,1 代表持有锁,>1 代表重入
  • wait/notify |Condition 需要唤醒指定线程 Lock support.park();-> unpark()
  • 双向链表实现 FIFO
  • 逻辑层实现公平和非公平锁
  • 在某一个地方存储当前获得锁的线程的Id,判断是否是持有锁的线程。

lock()

/**
* The current owner of exclusive mode synchronization.
*/
private transient Thread exclusiveOwnerThread;

/**
* The synchronization state.
*/
private volatile int state;
final void lock() {
// 比较是否无锁,乐观锁比较
	if (compareAndSetState(0, 1))
    	// 无锁设置当前线程拥有锁
       	setExclusiveOwnerThread(Thread.currentThread());
   else
   	// 再次抢占锁
     acquire(1);
}
 publi c final void acquire(int arg) {
      if (!tryAcquire(arg) &&
          acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
          selfInterrupt();
 }
  • !tryAcquire(arg) 抢占锁
  • acquireQueued 尝试抢占锁,不成功阻塞等待
  • addWaiter 初始化,在队尾添加节点
final boolean nonfairTryAcquire(int acquires) {
	// 获取当前线程
      final Thread current = Thread.currentThread();
      int c = getState();
      if (c == 0) {
      	  // 无锁,抢占锁
          if (compareAndSetState(0, acquires)) {
         	  // 无锁设置当前线程拥有锁
              setExclusiveOwnerThread(current);
              return true;
          }
      }
      // 判断是否重入锁
      else if (current == getExclusiveOwnerThread()) {
     	 // 重入锁,增加state值
          int nextc = c + acquires;
          if (nextc < 0) // overflow
              throw new Error("Maximum lock count exceeded");
          setState(nextc);// 已经是独占状态,不需要通过cas
          return true;
      }
      return false;
}
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 = tail;
    if (pred != null) {
        node.prev = pred;
         // cas 设置链表tail为插入的node 节点
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    enq(node);
    return node;
}

private Node enq(final Node node) {
    for (;;) {
        Node t = tail;
        if (t == null) { // Must initialize
        	// cas 初始化链表,添加一个空的头节点
            if (compareAndSetHead(new Node()))
                tail = head;
        } else {
            node.prev = t;
            // cas 设置链表tail为插入的node 节点
            if (compareAndSetTail(t, node)) {
                t.next = node;
                return t;
            }
        }
    }
}
final boolean acquireQueued(final Node node, int arg) {
    boolean failed = true;
    try {
        boolean interrupted = false;
        for (;;) {
        	 // 获取node的前继节点
            final Node p = node.predecessor();
            // 是头节点的话,也就是node为第二个节点,尝试获取锁
            if (p == head && tryAcquire(arg)) {
            	 // 获取锁成功,则更新头节点为当前节点,消除冗余节点
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
              // node不是头节点或者获取锁失败,执行判断是否需要阻塞等待
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

unlock()

public void unlock() {
    sync.release(1);
}

public final boolean release(int arg) {
    if (tryRelease(arg)) {
    	// 唤醒头节点
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

protected final boolean tryRelease(int releases) {
	// 获取状态值
    int c = getState() - releases;
    // 判断当前线程是否持有锁
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    // 判断是否为重入锁
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    // 设置重入次数
    setState(c);
    return free;
}

ReentrantReadWriteLock

CountDownLatch

注意

  • AQS 中的 state 维护计数值
  • 当计数值==0,唤醒阻塞线程
  • latch.countDown()计算值减一
  • latch.await() 等待计数器为0时唤醒

Semaphore

注意

  • AQS 中的 state 维护令牌数
  • semaphore.acquire()申请信号量
  • semaphore.release()释放信号量

Condition

条件队列,线程被await操作挂起后放入条件队列,等待signal操作唤醒进入AQS队列

阻塞线程

public final void await() throws InterruptedException {
    if (Thread.interrupted())
        throw new InterruptedException();
    // 将当前线程构造成条件节点加入condition的条件队列尾部,node即为构造的节点
    Node node = addConditionWaiter();
    // 完全释放锁,wait是要释放当前持有锁的,返回释放锁之前状态
    int savedState = fullyRelease(node);
    int interruptMode = 0;
    // isOnSyncQueue为true代表node已被转移到AQS队列;
    while (!isOnSyncQueue(node)) {
        LockSupport.park(this);
        if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
            break;
    }
    // 获取锁
    if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
        interruptMode = REINTERRUPT;
    if (node.nextWaiter != null) // clean up if cancelled
        unlinkCancelledWaiters();
    if (interruptMode != 0)
        reportInterruptAfterWait(interruptMode);
}

唤醒线程

public final void signal() {
	// 是否占有锁
    if (!isHeldExclusively())
        throw new IllegalMonitorStateException();
    // 拿到Condition头节点
    Node first = firstWaiter;
    if (first != null)
    	// 唤醒头节点
        doSignal(first);
}

private void doSignal(Node first) {
    do {
    	// 判断Condition队列头节点后继节点是否为空
        if ( (firstWaiter = first.nextWaiter) == null)
            lastWaiter = null;
        first.nextWaiter = null;
    } while (!transferForSignal(first) &&
             (first = firstWaiter) != null);
}

final boolean transferForSignal(Node node) {
    /*
     * If cannot change waitStatus, the node has been cancelled.
     */
    if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
        return false;

    // 把node加入AQS队列
    Node p = enq(node);
    int ws = p.waitStatus;
    // ws>0 是cancel状态,抛出异常后状态会变为cancel
    if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
    	// 节点拿到独占锁,直接唤醒
        LockSupport.unpark(node.thread);
    return true;
}