队列同步器(AQS:AbstractQueuedSynchronizer )
AQS是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。
AbstractQueuedSynchronizer是一个抽象方法。AQS的使用方式是继承。子类通过实现AbstractQueuedSynchronizer的抽象方法来管理同步状态。AbstractQueuedSynchronizer中有一个volatile int state来记录代表这个同步状态。主要通过以下3个方法获取或者改变同步状态:
①getState():获取当前同步状态。
②setState(int newState):设置当前同步状态。
③compareAndSetState(int expect,int update):使用CAS设置当前状态,该方法能够保证状态设置的原子性。
AQS使用的设计模式,模板方法设计模式。
模板方法设计模式AQS的基本思想CLH队列锁,每一个需要拿锁的线程打包成一个节点,挂到链表上,每个线程不断自旋检测前一个节点是否释放锁,释放锁当前线程就可以拿到这把锁。
CLH队列锁是一种基于链表(双向链表)的可扩展、高性能、公平的自旋锁,申请线程仅仅在本地变量上自旋,它不断轮询前驱的状态,假设发现前驱释放了锁就结束自旋。
结构:QNode,包含myPred(前驱结点)和Locked(当前是否需要获得锁,true为锁需求)。仅当myPred前驱结点值为false时。该QNode节点才能拿到锁。所以链表内的每个节点都在不断的自旋检查myPred的前驱结点Locked是否为false。
假设有A和B 2个线程。A和B分别创建2个QNode。A和B都需要拿到锁。
(1)当A拿到锁,A的myPred=true,locked=true.B的myPred=QNodeA,locked=true.
(2)B开始自旋它的前节点 locked是否为false,为false时代表A释放锁。
(3)A释放锁B拿到锁时,A的myPred=true,locked=false,B的myPred=true,locked=true.
(4)若还有C、D、E类似节点重复(1)(2)(3)。
AQS实际节点。AQS优化了CLH思想,拿不到锁的节点会自旋一定次数后就挂起节点。实际synchronized也是实现CLH队列锁的思想来实现的。区别在于AQS的的等待队列有多个,synchronized等待队列只有1个。
使用:
独占式实现以下2个方法。自行实现内容。
独占式共享式实现以下3个方法。自行实现内容。
共享式实现类似ReentrantLock功能(供参考,具体需求具体自行实现):
公平锁:必须按部就班的排队等待拿锁。(也称独占锁)
非公平锁:可插队拿锁,时间片轮转机制轮到谁就给谁。
网友评论