AQS详解
4. AQS
4.1. AQS的认识
1)所属层次
2)AQS介绍
AQS(AbstractQueuedSynchronizer)就是抽象的队列式的同步器,是一个Java提供的底层同步工具类,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,用一个int类型的变量表示同步状态,并提供了一系列的CAS操作来管理这个同步状态。
3)AQS主要作用
AQS的主要作用是为Java中的并发同步组件提供统一的底层支持,如常用的ReentrantLock/Semaphore/CountDownLatch等等就是基于AQS实现的。
4)AQS使用方法
用法是通过继承AQS实现其模版方法,然后将子类作为同步组件的内部类。
5)同步队列
同步队列是AQS很重要的组成部分,它是一个双端队列,遵循FIFO原则,主要作用是用来存放在锁上阻塞的线程,当一个线程尝试获取锁时,如果已经被占用,那么当前线程就会被构造成一个Node节点加入到同步队列的尾部,队列的头节点是成功获取锁的节点,当头节点线程释放锁时,会唤醒后面的节点并释放当前头节点的引用。
同步队列维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。state的访问方式有三种:
getState()
setState()
compareAndSetState()
6)资源共享方式
AQS定义两种资源共享方式:
Exclusive 独占,只有一个线程能执行,如ReentrantLock
Share 共享,多个线程可同时执行,如Semaphore/CountDownLatch
不同的自定义同步器争用共享资源的方式也不同,一般来说,自定义同步器要么是独占方法,要么是共享方式,只需实现tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一种即可。但AQS也支持自定义同步器同时实现独占和共享两种方式,如ReentrantReadWriteLock。
自定义同步器实现时主要实现以下几种方法:
isHeldExclusively() 该线程是否正在独占资源。只有用到condition才需要去实现它。
tryAcquire(int) 独占方式。尝试获取资源,成功则返回true,失败则返回false。
tryRelease(int) 独占方式。尝试释放资源,成功则返回true,失败则返回false。
tryAcquireShared(int) 共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
tryReleaseShared(int) 共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false
具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了。