java 并发开发之AQS
- AQS 是什么,有什么作用?
① 是什么:AQS 是抽象队列同步器,AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖它
② 有什么作用:为Java的并发同步组件提供统一的底层支持,ReentrantLock、Semaphore、CountDownLatch等 - AQS 的原理
AQS 的实现依赖FIFO双向队列(CLH队列锁的变体)和 volatile的state变量(共享资源状态)
如果当前线程竞争失败,AQS会把当前线程及等待信息(Node节点)加入到队列中,同时阻塞该线程。当获取锁的线程释放锁之后,会从队列中唤醒一个阻塞的节点。
volatile 能够保证多线程下的可见性,state的操作都是通过CAS来保证其并发修改的安全性
- CLH锁
CLH锁是自旋锁(spinlock),能够保证无饥饿性,提供先来先服务的公平性
CLH基于链表实现,线程在不断的自旋,不断地轮询前驱节点的状态,如果前驱节点释放了锁,那么线程结束自旋
对于持锁时间很短的场景,比之前把线程阻塞住具有更高的想能,并能保证一定的公平性 - AQS 底层数据结构,Node节点有哪些状态
AQS 底层数据结构是使用的双向链表,sync queue即同步队列,是双向链表,包括head节点和tail节点,head节点主要用作后续的调度。
Node节点状态waitStatus:
① 每个节点初始状态为0
② CABCELLED,值为1,表示当前线程被取消
③ SIGNAL,值为-1,表示该节点的后续节点被挂起了,当释放锁或者取消时,需要唤醒后续节点
④ CONDITION,值为-2,表示节点处于Condition队列中
⑤ PROPAGATE,值为-3,用于共享锁,表示下一次尝试获取共享锁时,需要无条件传播下去
Node 可能是共享式的,可能是独占式的
Node 有两种构造函数
Node(Thread thread, Node mode) { //Used by addwaiter
this.nextWaiter = mode;
this.thread= thread;
}
Node(Thread thread, int waitStatus) { //Used by Condition
this.waitStatus = waitStatus;
this.thread= thread;
}
- AQS 对资源有哪些共享方式
两种:共享share,独占Exclusive
① 共享
多个线程可以同时执行,如Semaphore、CountDownLatch、CyclicBarrier、ReentrantReadWriteLock.ReadLock
② 独占
只有一个线程能执行,如ReentrantLock、ReentrantReadWriteLock.WriteLock - AQS 底层实现,用了什么设计模式
AQS 同步器的设计是基于模板方法模式
模板方法模式是基于继承的,主要是为了在不改变模板结构的前提下在子类中重新定义模板中的内容以实现代码复用。
- 自定义同步器时需要重写下面几个AQS提供的模板方法:
isHeldExclusively() //该线程是否正在独占资源。只有用到condition才需要去实现它。
tryAcquire(int) //独占方式。尝试获取资源,成功则返回true,失败则返回false。
tryRelease(int) //独占方式。尝试释放资源,成功则返回true,失败则返回false。
tryAcquireShared(int) //共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。
tryReleaseShared(int) //共享方式。尝试释放资源,成功则返回true,失败则返回false。