AQS源码浅析
作者:互联网
一、AQS简介
AbstractQueuedSynchronizer 抽象队列同步器。简称AQS,同时拥有 同步队列 与 等待队列
二、源码浅析
- 同步队列
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
2. 等待队列
调用 await 方法,进入condition的等待队列,释放锁,进入一个 while 循环,只有当线程回到同步队列或者被中断才可以跳出while,while里面 park 掉线程 ----- 在 condition调用 signal 之后,该condition上面的节点的 firstWaiter 首先加入到 同步队列尾部 , 会 unpark 线程,退出 while 之后,又会进入 acquireQueued 的循环里面,同样存在之前的逻辑。
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); int interruptMode = 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); }
3. 总结
-
- 等待队列,是已经获取到锁的线程,需要用到其他线程的数据,主动调用 wait() 方法,并且释放锁,唤醒同步队列的后继节点(非公平不用唤醒),然后当前节点构造新的Node进入等待队列,当有其他 在同步队列里面 已经获得锁的线程调用 notify()(或者 signal())之后,才会重新加入同步队列,尝试获取锁。 等待队列的节点也调用了 park () 方法阻塞。
- Condition 接口中的 await() 与 signal() 函数分别用于 是线程进行等待状态---加入到等待队列中 、唤醒等待队列中的首节点的线程。
- 在ReetrantLock 里面,公平与非公平自旋锁,也是基于 同步器的,同步器的队列是默认阻塞的 ,ReetrantLock 里面是自旋非阻塞的。compareAndSetState
- ReetrantLock 里面 公平与非公平的自旋锁,都是在一直自旋没有 park(), 公平多了一个判断当前节点是否有前驱节点语句
if (!hasQueuedPredecessors()...
三、工具类
- LockSupport
转载请注明地址:https://www.cnblogs.com/handsomecui/p/14253284.html
标签:node,调用,AQS,队列,同步器,while,源码,线程,浅析 来源: https://www.cnblogs.com/handsomecui/p/14253284.html