初识Lock与AbstractQueuedSynchronizer(AQS) - omigaw/spring- GitHub Wiki

1. concurrent包的结构层次

java.util.concurrent包下,有分装好的,大量实用的工具。
* atomic
* locks
   * AbstractExecutorService
   * ArrayBlockingQueue
   * BlockingDeque
   * BlockingQueue
   * BrokenBarrierException
   * Callable
   * CancellationException
   * CompletableFuture
   * CompletionException
   * CompletionService
   * CompletionStage
   * ConcurrentHashMap
   * ConcurrentLinkedDeque
其中包含了两个子包:atomic以及lock,另外在concurrent下的阻塞队列以及executors,这些就是concurrent包中的精华,而这些类的实现主要依赖于volatile以及CAS。

2. Lock简介

在Lock接口出现之前,java程序主要是靠synchronized关键字实现锁功能的,而java SE5之后,并发包中增加了lock接口,它提供了于synchronized一样的锁功能。
虽然它失去了像synchronized关键字隐式加锁解锁的便捷性,但是却拥有了锁获取和释放得可操作性,可中断的获取锁以及超时获取锁等多种synchronized关键字所不具备的同步特性。
`Lock lock = new ReentrantLock();
 lock.lock();
 try{
      ......  
 }finally{
      lock.unlock();
 }`
需要注意的是**synchronized同步块执行完成或者遇到异常时锁会自动释放,而lock必须调用unlock()方法释放锁,因此在finally块中释放锁**。
ReentrantLock实现了lock接口,基本上所有的方法得实现实际上都是调用了其静态内存类sync中的犯法,而Sync类继承了AbstractQueuedSynchronizer(AQS)。可以看出要想理解ReentrantLock关键核心在于对队列同步器AbstractQueuedSynchronizer(简称同步器)的理解。

3. 初识AQS

同步器是用来构建锁和其他同步组件的基础框架,它的实现主要依赖一个int成员变量来表示同步状态以及通过一个FIFO队列构成等待队列。它的**子类必须重写AQS的几个protected修饰的用来改变同步状态的方法**,其他方法主要是实现了排队和阻塞机制。**状态的更新使用getState、setState以及compareAndSetState这三个方法。**
子类被**推荐定义为自定义同步组件的静态内部类**,同步器自身没有实现任何同步接口,它仅仅是定义了若干同步状态的获取和释放方法来供自定义同步组件的使用,同步器既支持独占式获取同步状态,也可以支持共享式获取同步状态,这样就可以方便的实现不同类型的同步组件。
同步器是实现锁(也可以是任意同步组件)的关键,在锁的实现中聚合同步器,利用同步器实现锁的语义。可以这样理解二者的关系:**锁是面向使用者,它定义了使用者与锁交互的接口,隐藏了实现细节;同步器是面向锁的实现者,它简化了锁的实现方式,屏蔽了同步状态的管理,线程的排队,等待和唤醒等底层操作。**锁和同步器很好的隔离了使用者和实现者所需关注的领域。

4. AQS的模板方法设计模式

AQS的设计是使用模板方法设计模式,它将**一些方法开放给子类进行重写,而同步器给同步组件所提供模板方法又会重新调用被子类所重写的方法**。
AQS提供的模板方法可以分为3类:
1.独占式获取与释放同步状态;
2.共享式获取与释放同步状态;
3.查询同步队列中等待线程情况;
同步组件通过AQS提供的模板方法实现自己的同步语义。

通俗点说,因为AQS整体设计思路采用模板方法设计模式,同步组件以及AQS的功能实际上切分成各自的两个部分:

同步组件实现者的角度: 通过可重写的方法:独占式:tryAcquire()(独占式获取同步状态),tryRelease()(独占式释放同步状态);共享式:tryAcquireShared()(共享式获取同步状态),tryReleaseShared()(共享式释放同步状态);告诉AQS怎样判断当前同步状态是否成功获取或者是否成功释放。

AQS的角度 而对AQS来说,只需要同步组件返回的true和false即可,因为AQS会对true和false会有不同的操作,true会认为当前线程获取同步组件成功直接放回,而false的话也会将当前线程插入同步队列等一系列的方法。 总的来说,同步组件通过重写AQS的方法实现自己想要表达的同步语义,而AQS只需要同步组件表达的true和false即可,AQS会针对false不同的情况做不同的处理。