Java并发编程之AQS

一、什么是AQS

  AQS(AbstractQueuedSynchronize:队列同步器)是用来构建锁或者其他同步组件的基础框架,很多同步类都是在它的基础上实现的,比如常用的ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore。

二、实现原理

  在AQS内部,定义了一个 volatile int state 变量来标识同步状态,通过改变state的状态来控制对共享资源的访问,根据不同的实现,state可以表示不同的状态,例如:在 ReentrantLock 中它表示拥有该锁的线程请求了多少次该锁;在 Semaphore 中表示剩余的许可数,在 FutureTask 中表示任务的状态(尚未开始、运行、完成和取消)。同时定义了一个 FIFO 队列维护争用资源时被阻塞的线程,当线程尝试获取锁时,如果锁已经被占用,那么该线程就会被构造成一个Node节点放到同步队列的尾部;队列的头节点是成功获取锁的节点,当头节点线程释放锁时,会唤醒后面的节点并释放当前头节点的引用。AQS主要通过继承的方式来使用,子类通过继承AQS并实现它的抽象方法来定义state变量的具体的访问规则,从而可以实现不同类型的同步组件。AQS自身没有实现任何同步接口,为了保证对state的访问修改操作是安全的,AQS提供了以下三个方法供自定义同步组件使用:

  1. getState():获取当前同步状态。
  2. setState(int newState):设置当前同步状态。
  3. compareAndSetState(int expect,int update):使用CAS设置当前状态,该方法能够保证状态设置的原子性。

  AQS是实现锁的关键,它在底层对同步状态管理、线程的排队、等待与唤醒做了实现,简化锁的实现。

  AQS定义了两种资源共享的方式:独占式和共享式。

  1. 独占式:同时只有一个线程能访问该共享资源。
  2. 共享式:多个线程可以同时访问该共享资源。

  AQS是基于模板方法模式设计的,它提供了一些模板方法,自定义同步器时重写这些方法。这些模板方法如下:

  1. protected boolean tryAcquire(int arg):独占式获取同步状态,成功则返回true,失败则返回false。先查询同步状态并判断同步状态是否符合预期,然后再进行CAS设置同步状态。
  2. protected boolean tryRelease(int arg):独占式释放同步状态,成功则返回true,失败则返回false。等待获取同步状态的线程将有机会获取同步状态。
  3. protected int tryAcquireShared(int arg):共享式获取同步状态,返回大于等于0的值,表示成功,该值表示剩余可用资源数,小于0则表示获取失败。
  4. protected boolean tryReleaseShared(int arg):共享式释放同步状态,如果释放后允许唤醒后续等待结点返回true,否则返回false。
  5. protected boolean isHeldExclusively():当前同步器是否在独占模式下被线程占用,只在 AbstractQueuedSynchronizer.ConditionObject 方法内进行内部调用,不使用Condition可以不实现。

猜你喜欢

转载自www.cnblogs.com/Mr-XiaoLiu/p/9985408.html