Java中的队列同步器AQS

一、AQS概念

  1、队列同步器是用来构建锁或者其他同步组件的基础框架,使用一个int型变量代表同步状态,通过内置的队列来完成线程的排队工作。

  2、下面是JDK8文档中对于AQS的部分介绍

  public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable
  提供一个框架,用于实现依赖先进先出(FIFO)等待队列的阻塞锁和相关同步器(信号量,事件等)。 该类被设计为大多数类型的同步器的有用依据,这些同步器依赖于单个原子int值来表示状
态。子类必须定义改变此状态的protected方法,以及根据该对象被获取或释放来定义该状态的含义。给定这些,这个类中的其他方法执行所有排队和阻塞机制。 子类可以保持其他状态字段,但只以
原子方式更新int使用方法操纵值getState() , setState(int)和compareAndSetState(int, int)被跟踪相对于同步。   
此类支持默认独占模式和共享模式。 当以独占模式获取时,尝试通过其他线程获取不能成功。 多线程获取的共享模式可能(但不需要)成功。 除了在机械意义上,这个类不理解这些差异,当共享
模式获取成功时,下一个等待线程(如果存在)也必须确定它是否也可以获取。 在不同模式下等待的线程共享相同的FIFO队列。 通常,实现子类只支持这些模式之一,但是两者都可以在
ReadWriteLock中发挥作用。仅支持独占或仅共享模式的子类不需要定义支持未使用模式的方法。

  总结来说就是:

  ①子类通过继承AQS并实现其抽象方法来管理同步状态,对于同步状态的更改通过提供的getState()、setState(int state)、compareAndSetState(int expect, int update)来进行操作,因为使用CAS操作保证同步状态的改变是原子的

  ②子类被推荐定义为自定义同步组件的静态内部类,同步器本身并没有实现任何的同步接口,仅仅是定义了若干状态获取和释放的方法来提供自定义同步组件的使用。

  ③同步器既可以支持独占式的获取同步状态,也可以支持共享式的获取同步状态(ReentrantLock、ReentrantReadWriteLock、CountDownLatch等不同类型的同步组件)

  3、同步器是实现锁的关键,在锁的实现中聚合同步器,利用同步器实现锁的语义;

二、AQS的接口和实例

1、同步器的设计实现原理

  继承同步器并且重写指定的方法,然后将同步器组合在自定义同步组件的实现中,并且调用同步器提供的模板方法(这些模板方法会调用重写的方法);而重写指定的方法的时候,需要使用getState()、setState(int state)、compareAndSetState(int expect, int update)来访问或者更新同步状态。下面是源码中state变量和三个方法的定义声明实现

 1     /**
 2      * The synchronization state.(同步状态)
 3      */
 4     private volatile int state;
 5 
 6     /**
 7      * Returns the current value of synchronization state.(返回当前的同步状态)
 8      * This operation has memory semantics of a {@code volatile} read.
 9      * 此操作的内存语义为@code volatile read
10      * @return current state value
11      */
12     protected final int getState() {
13         return state;
14     }
15 
16     /**
17      * Sets the value of synchronization state.(设置新的同步状态)
18      * This operation has memory semantics of a {@code volatile} write.
19      * 此操作的内存语义为@code volatile read
20      * @param newState the new state value
21      */
22     protected final void setState(int newState) {
23         state = newState;
24     }
25 
26     /**
27      * Atomically sets synchronization state to the given updated
28      * value if the current state value equals the expected value.(如果要更新的状态和期望的状态相同,那就通过原子的方式更新状态)
29      * This operation has memory semantics of a {@code volatile} read
30      * and write.( 此操作的内存语义为@code volatile read 和 write)
31      *
32      * @param expect the expected value
33      * @param update the new value
34      * @return {@code true} if successful. False return indicates that the actual
35      *         value was not equal to the expected value.(如果更新的状态和期望的状态不同就返回false)
36      */
37     protected final boolean compareAndSetState(int expect, int update) {
38         // See below for intrinsics setup to support this
39         return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
40     }

2、下面介绍AQS提供可被重写的方法

  ①tryAcquire()方法

/**
 * 独占式的获取同步状态,实现该方法需要查询当前状态并判断同步状态是否符合预期,然后再进行CAS设置同步状态
 *
 */
protected boolean tryAcquire(int arg) {
    throw new UnsupportedOperationException();
}

  ②tryRelease()方法

/**
 * 独占式的释放同步状态,等待获取同步状态的线程可以有机会获取同步状态
 *
 */
protected boolean tryRelease(int arg) {
    throw new UnsupportedOperationException();
}

  ③tryAcquireShared()方法

/**
 * 尝试以共享模式获取。 该方法应该查询对象的状态是否允许在共享模式下获取该对象,如果是这样,就可以获取它。 该方法总是由执行获取的线程调用。
* 如果此方法报告失败,则获取方法可能将线程排队(如果尚未排队),直到被其他线程释放为止。 获取失败时返回负值,如果在获取成共享模式下功但没
* 有后续共享模式获取可以成功,则为零; 并且如果以共享模式获取成功并且随后的共享模式获取可能成功,则为正值,在这种情况下,后续等待线程必须检查可用性。
*/ protected int tryAcquireShared(int arg) { throw new UnsupportedOperationException(); //如果不支持共享模式 ,会抛出该异常 }

  ④tryReleaseShared()方法

/**
 * 尝试将状态设置为以共享模式释放同步状态。 该方法总是由执行释放的线程调用。 
 */
protected int tryReleaseShared(int arg) {
    throw new UnsupportedOperationException(); //如果不支持共享模式 ,会抛出该异常
}

  ⑤isHeldExclusively() 方法

/**
 * 当前同步器是否在独占模式下被线程占用,一般该方法表示是否被当前线程所独占
 */
protected int isHeldExclusively(int arg) {
    throw new UnsupportedOperationException(); //如果不支持共享模式 ,会抛出该异常
}

   3、同步器提供的模板方法

  在实现自定义同步组件的时候,需要重写上面的方法,而下面的模板方法会调用上面重写的方法。下面介绍同步器提供的模板方法

  ①acquire()方法

/**
 * 以独占模式获取,忽略中断。 通过调用至少一次tryAcquire(int)实现,成功返回。 否则线 
 * 程排队,可能会重复阻塞和解除阻塞,直到成功才调用tryAcquire(int) 
 */
public final void acquire(int arg) {...}

   ②acquireInterruptibly()方法

/**
 * 以独占方式获得,如果中断,中止。 通过首先检查中断状态,然后调用至少一次
 * tryAcquire(int) ,成功返回。 否则线程排队,可能会重复阻塞和解除阻塞,调用
 * tryAcquire(int)直到成功或线程中断。
 */
public final void acquireInterruptibly(int arg) throws InterruptedException {...}

   ③tryAcquireNanos()方法

/**
 * 尝试以独占模式获取,如果中断则中止,如果给定的超时时间失败。 首先检查中断状态,然
 * 后调用至少一次tryAcquire(int) ,成功返回。 否则,线程排队,可能会重复阻塞和解除阻
 * 塞,调用tryAcquire(int)直到成功或线程中断或超时
 */
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {...}

  ④acquireShared()方法

/**
 * 以共享模式获取,忽略中断。 通过首次调用至少一次执行 tryAcquireShared(int),成功返
 * 回。 否则线程排队,可能会重复阻塞和解除阻塞,直到成功调用tryAcquireShared(int) 。
 */
public final void acquireShared(int arg){...}

   ⑤acquireSharedInterruptibly()方法

/**
 * 以共享方式获取,如果中断,中止。 首先检查中断状态,然后调用至少一次
 * tryAcquireShared(int) ,成功返回。 否则线程排队,可能会重复阻塞和解除阻塞,调用
 * tryAcquireShared(int)直到成功或线程中断。
 */
public final void acquireSharedInterruptibly(int arg) throws InterruptedException{...}

  ⑥tryAcquireSharedNanos()方法

/**
 * 尝试以共享模式获取,如果中断则中止,如果给定的时间超过,则失败。 通过首先检查中断 
 * 状态,然后调用至少一次tryAcquireShared(int) ,成功返回。 否则,线程排队,可能会重 
 * 复阻塞和解除阻塞,调用tryAcquireShared(int)直到成功或线程中断或超时。 
 */
public final boolean tryAcquireSharedNanos(int arg, long nanosTimeout) throws InterruptedException{...}

   ⑦release()方法

/**
 * 独占式的释放同步状态,该方法会在释放同步状态之后,将同步队列中的第一个节点包含的线程唤醒
 */
public final boolean release(int arg){...}

  ⑧releaseShared()方法

/**
 * 共享式的释放同步状态
 */
public final boolean releaseShared(int arg){...}

  ⑨getQueuedThreads()方法

/**
 * 获取在等待队列上的线程集合
 */
public final Collection<Thread> getQueuedThreads(){...}

猜你喜欢

转载自www.cnblogs.com/fsmly/p/10701109.html