Java并发包之核心AQS

362 阅读2分钟

AQS是什么?

AQS全称(AbstractQueuedSynchronizer)在jdk并发包中的多个API中被使用,他通过(FIFO)队列原理是想了作用和关键字synchronizers相似的功能。这个类是为了大多数以来单个原子(int)值表示状态的同步器提供基础处理。例如:CountDownLatch中提供的SYNC内部类。子类须要按需重写它的受保护的方法分别是:tryAcquireShared,tryReleaseShared,tryAcquire和tryRelease,isHeldExclusively,还需要在构造函数中传入原子状态int 拿CountDownLatch举例:

private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }
        
	// 在await方法中调用,当getState(原子变量)不为0的时候使其阻塞
        // 其原理是通过AbstractQueuedSynchronizer的内置对象Node(Node拥有prev节点和next节点)通过Node节点的自旋判定是否是头部节点
        // 如果是头部节点则取得锁
        protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

		// 在countDown方法中被调用,每次调用都会将getState(原子变量)减去1
        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
    }
}

tryAcquireShared、tryReleaseShared 和 tryAcquire、tryRelease的区别在于

AQS定义了两种资源共享方式:

  • Exclusive:独占,只有一个线程能执行,如ReentrantLock
  • Share:共享,多个线程可以同时执行,如Semaphore、CountDownLatch、ReadWriteLock,CyclicBarrier

独占和共享的概念是针对占用资源的节点的角度来说的,等待资源的节点始终都是一个。

FIFO队列

CLH(Craig,Landin,and Hagersten)队列是一个虚拟的双向队列,虚拟的双向队列即不存在队列实例,仅存在节点之间的关联关系。AQS是将每一条请求共享资源的线程封装成一个CLH锁队列的一个结点(Node),来实现锁的分配。 AQS具体实现方法如下:
alt

如图等待资源线程通过队列中节点自旋判断是否是头节点来判定是否获取到资源。