目录
- 一、AQS的理解
- 二、AQS定义的两种资源共享方式
- 三、AQS的使用
- 四、同步器的实现是ABS核心(state资源状态计数)
- 五、ReentrantReadWriteLock实现独占和共享两种方式
- 六、AQS中的方法摘要(以下内容摘自JDK1.8版本在线中文文档)
- 七、JDK1.8版本在线中文文档
一、AQS的理解
- AQS是AbstractQueuedSynchronizer的简称,JDK1.5以后才出现,属于java.util.concurrent.locks包下的类。
- AbstractQueuedSynchronizer类如其名,抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch。
- 它维护了一个volatile int state(代表共享资源)和一个FIFO线程等待队列(多线程争用资源被阻塞时会进入此队列)。这里volatile是核心关键词,具体volatile的语义,在此不述。state的访问方式有三种:
- getState()
- setState()
- compareAndSetState()
二、AQS定义的两种资源共享方式
1、 Exclusive独占资源-ReentrantLock
- Exclusive(独占,只有一个线程能执行,如ReentrantLock)
2、Share共享资源-Semaphore/CountDownLatch
- Share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)。
三、AQS的使用
-
AQS只是一个框架,具体资源的获取/释放方式交由自定义同步器去实现,AQS这里只定义了一个接口,具体资源的获取交由自定义同步器去实现了(通过state的get/set/CAS)之所以没有定义成abstract, 是 因 为 独 占 模 式 下 只 用 实 现tryAcquire-tryRelease, 而 共 享 模 式 下 只 用 实 现tryAcquireShared-tryReleaseShared。如果都定义成abstract,那么每个模式也要去实现另一模式下的接口。不同的自定义同步器争用共享资源的方式也不同。自定义同步器在实现时只需要实现共享资源state的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了。自定义同步器实现时主要实现以下几种方法:
-
tryAcquire(int): 独占方式。尝试获取资源,成功则返回true,失败则返回false
-
tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。
-
tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
-
tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。
-
isHeldExclusively() :该线程是否正在独占资源。只有用到condition才需要去实现它。
四、同步器的实现是ABS核心(state资源状态计数)
- 同步器的实现是ABS核心,以ReentrantLock为例,state初始化为0,表示未锁定状态。A线程lock()时,会调用tryAcquire()独占该锁并将state+1。此后,其他线程再tryAcquire()时就会失败,直到A线程unlock()到state=0(即释放锁)为止,其它线程才有机会获取该锁。当然,释放锁之前,A线程自己是可以重复获取此锁的(state会累加),这就是可重入的概念。但要注意,获取多少次就要释放多么次,这样才能保证state是能回到零态的。
- 以CountDownLatch以例,任务分为N个子线程去执行,state也初始化为N(注意N要与线程个数一致)。这N个子线程是并行执行的,每个子线程执行完后countDown()一次,state会CAS减1。等到所有子线程都执行完后(即state=0),会unpark()主调用线程,然后主调用线程就会从await()函数返回,继续后余动作。
五、ReentrantReadWriteLock实现独占和共享两种方式
- 一般来说,自定义同步器要么是独占方法,要么是共享方式,他们也只需实现tryAcquire-tryRelease、tryAcquireShared-tryReleaseShared中的一种即可。但AQS也支持自定义同步器同时实现独占和共享两种方式,如ReentrantReadWriteLock。
六、AQS中的方法摘要(以下内容摘自JDK1.8版本在线中文文档)
| 序号 | 返回值 | 方法名称及解释 |
|---|---|---|
| 1 | void | acquire(int arg) 以独占模式获取对象,忽略中断。 |
| 2 | void | acquireInterruptibly(int arg) 以独占模式获取对象,如果被中断则中止。 |
| 3 | void | acquireShared(int arg) 以共享模式获取对象,忽略中断。 |
| 4 | void | acquireSharedInterruptibly(int arg) 以共享模式获取对象,如果被中断则中止。 |
| 5 | protected boolean | compareAndSetState(int expect, int update) 如果当前状态值等于预期值,则以原子方式将同步状态设置为给定的更新值。 |
| 6 | Collection < thread> | getExclusiveQueuedThreads() 返回包含可能正以独占模式等待获取的线程 collection。 |
| 7 | Thread | getFirstQueuedThread() 返回队列中第一个(等待时间最长的)线程,如果目前没有将任何线程加入队列,则返回 null. 在此实现中,该操作是以固定时间返回的,但是,如果其他线程目前正在并发修改该队列,则可能出现循环争用。 |
| 8 | Collection < thread> | getQueuedThreads() 返回包含可能正在等待获取的线程 collection。 |
| 9 | int | getQueueLength() 返回等待获取的线程数估计值。 |
| 10 | Collection< Thread> | getSharedQueuedThreads() 返回包含可能正以共享模式等待获取的线程 collection。 |
| 11 | protected int | getState() 返回同步状态的当前值。 |
| 12 | Collection< Thread> | getWaitingThreads(AbstractQueuedSynchronizer.ConditionObject condition) 返回一个 collection,其中包含可能正在等待与此同步器有关的给定条件的那些线程。 |
| 13 | int | getWaitQueueLength(AbstractQueuedSynchronizer.ConditionObject condition) 返回正在等待与此同步器有关的给定条件的线程数估计值。 |
| 14 | boolean | hasContended() 查询是否其他线程也曾争着获取此同步器;也就是说,是否某个 acquire 方法已经阻塞。 |
| 15 | boolean | hasQueuedThreads() 查询是否有正在等待获取的任何线程。 |
| 16 | boolean | hasWaiters(AbstractQueuedSynchronizer.ConditionObject condition) 查询是否有线程正在等待给定的、与此同步器相关的条件。 |
| 17 | protected boolean | isHeldExclusively() 如果对于当前(正调用的)线程,同步是以独占方式进行的,则返回 true。 |
| 18 | boolean | isQueued(Thread thread) 如果给定线程的当前已加入队列,则返回 true。 |
| 19 | boolean | owns(AbstractQueuedSynchronizer.ConditionObject condition) 查询给定的 ConditionObject 是否使用了此同步器作为其锁。 |
| 20 | boolean | release(int arg) 以独占模式释放对象。 |
| 21 | boolean | releaseShared(int arg) 以共享模式释放对象。 |
| 22 | protected void | setState(int newState) 设置同步状态的值。 |
| 23 | String | toString() 返回标识此同步器及其状态的字符串。 |
| 24 | protected boolean | tryAcquire(int arg) 试图在独占模式下获取对象状态。 |
| 25 | boolean | tryAcquireNanos(int arg, long nanosTimeout) 试图以独占模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。 |
| 26 | protected int | tryAcquireShared(int arg) 试图在共享模式下获取对象状态。 |
| 27 | boolean | tryAcquireSharedNanos(int arg, long nanosTimeout) 试图以共享模式获取对象,如果被中断则中止,如果到了给定超时时间,则会失败。 |
| 28 | protected boolean | tryRelease(int arg) 试图设置状态来反映独占模式下的一个释放。 |
| 29 | protected boolean | tryReleaseShared(int arg) 试图设置状态来反映共享模式下的一个释放。 |
七、JDK1.8版本在线中文文档
https://www.matools.com/api/java8
