AQS
AQS介绍:
AbstractQuenedSynchronizer抽象的队列式同步器。
是一个底层锁机制,内部使用了模板方法设计模式,定义了独占式和共享式两种资源共享方式。
很多同步类都是依赖AQS实现的。
比如
1.Exclusive:独占,只有一个线程能执行,如ReentrantLock
2.Share:共享,多个线程可以同时执行,如Semaphore、CountDownLatch、CyclicBarrier
3.独占+共享:ReadWriteLock(读共享,写独占)
AQS原理:
AQS就是基于一个链表实现的双向队列(CLH),用volatile修饰共享变量state,线程通过CAS去改变state,成功则获取锁成功,失败则进入等待队列,等待被唤醒。队列里每个Node都存放了线程和头尾关系。
基于AQS实现自定义同步类:
是基于模板方法模式的
1.使用者继承AbstractQueuedSynchronizer并重写指定的方法(对state的获取和释放)
【
isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它。
tryAcquire(int):独占方式。尝试获取资源
tryRelease(int):独占方式。尝试释放资源
tryAcquireShared(int):共享方式。尝试获取资源。
tryReleaseShared(int):共享方式。尝试释放资源。】
2.将AQS组合在自定义同步组件的实现中,并调用其模板方法,而这些模板方法会调用使用者重写的方法,这是模板方法模式很经典的一个运用。
例:ReentrantLock:
重写tryAcquire()、tryRelease(),实现了可重入逻辑。
tryAcquire: tryRelease:
if(state=0)时, 每次state -1
当前线程CAS尝试获取独占资源,成功 return true; if(state == 0){
else if(当前线程 是 独占资源的线程 ), 当前线程释放独占资源
state+1, return true。 }
else
return false;
所以同一线程 lock多少次,就要unlock多少次。
(他的公平锁实现只是加了一层判断:是否有顺序在本线程前面的在队列排队)
独占锁获取详细过程:
1.本线程 CAS尝试获取独占锁2次
2.获取失败后,线程 CAS自旋尾插 到队列
3.在队列中,自旋 (判断如果前节点是头节点,且获取独占锁成功,则 return。 否则 设置前节点状态为SIGNAL(释放本节点,会通知唤醒下个节点),调用LookSupport.park阻塞本线程。)
4.本线程等待被唤醒后,继续3内自旋的过程。
独占锁释放详细过程:
1.释放锁,并判断并唤醒后续节点