实现原理_Condition 实现原理
Condition 實現原理
說 Codition 前,需要說下 ConditioObject。 ConditionObject 是同步器 AbstractQueuedSynchronzied 的內部類,因為 Condition 的操作需要關聯的鎖。 ArrayBlockingQueue 就是 Condition 的具體應用。 Object 中其實 也有 wait ,notify ,notifyAll 等操作, Condition 相當于將 wait ,notify ,notifyAll 轉換成想要的對象,將比較難懂的同步操作變成直觀可控的對象行為。
應用場景 ArrayBlockingQueue
ArrayBlockingQueue 的構造函數。
/** Main lock guarding all access */ final ReentrantLock lock;/** Condition for waiting takes */ private final Condition notEmpty;/** Condition for waiting puts */ private final Condition notFull; public ArrayBlockingQueue(int capacity, boolean fair) {if (capacity <= 0)throw new IllegalArgumentException();this.items = new Object[capacity];lock = new ReentrantLock(fair);notEmpty = lock.newCondition();notFull = lock.newCondition(); }通過構造函數,可以看到 Condition 的創建時需要關聯鎖的。
從隊列中去取出(take)數據 。
public E take() throws InterruptedException {final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {while (count == 0)notEmpty.await();return dequeue();} finally {lock.unlock();}}往隊列中加入數據 enqueue
private void enqueue(E x) {// assert lock.getHoldCount() == 1;// assert items[putIndex] == null;final Object[] items = this.items;items[putIndex] = x;if (++putIndex == items.length)putIndex = 0;count++;notEmpty.signal();}可以看主要用了 await signal 等方法。具體代表什么含義?
Condition 實現主要包含三個部分:等待隊列、等待、通知。
如果了解 AQS 原理可以知道, AQS 中有個同步隊列的概念。
等待隊列
等待隊列和同步隊列類似,都是一個 FIFO 隊列。隊列上每個節點包含一個線程引用,該線程就是 Condition 對象上的等待線程。等待隊列結構如下:
Condition 等待隊列,也是包含首節點(firstWaiter),和尾節點(tailWaiter),如果一個線程調用了 Condition.await() 方法。那么該線程將會釋放鎖,并以當前線程構造節點加入等待隊列并進入等待狀態。
Object 監視器模型
Object 監視器模型 包含了一個同步多路和多個等待隊列,結構如下所示:
等待
當調用 Condition 的 await() 方法(或者以 await開頭的方法),會使得當前線程進入等待隊列,并且釋放鎖,同時線程的狀態變為等待狀態。
public final void await() throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();// 當前線程加入等待隊列 Node node = addConditionWaiter();// 釋放同步狀態,也就是釋放鎖int savedState = fullyRelease(node);int interruptMode = 0;// node 不在節點中會一直 park 阻塞下去。達到等待的效果。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 cancelledunlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);}調用該方法的線程成功獲得了鎖的線程,也就是同步隊列的首節點,該方法將會將該線程構造成節點并加入等待隊列中,然后釋放同步狀態,喚醒同步隊列中的后續節點,然后當前節點會進入等待狀態。要注意的是,如果等地隊列中的節點被喚醒,喚醒節點的線程開始嘗試獲取同步狀態。但是如果不是通過 Condition.signal 進行喚醒的,而是對等待線程進行中斷,那么會拋出 InterruptedException。
調用 Condition signal 方法后,當前線程會加入到等待隊列,如下圖所示:
通知
調用 Condition.signal() 方法,將會喚醒等待隊列中等待時間最長的節點(首節點),在喚醒節點之前,會將節點移動到同步隊列中。
public final void signal() {if (!isHeldExclusively())throw new IllegalMonitorStateException();Node first = firstWaiter;if (first != null)doSignal(first);} final boolean transferForSignal(Node node) {/** If cannot change waitStatus, the node has been cancelled.*/if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))return false;/** Splice onto queue and try to set waitStatus of predecessor to* indicate that thread is (probably) waiting. If cancelled or* attempt to set waitStatus fails, wake up to resync (in which* case the waitStatus can be transiently and harmlessly wrong).*/Node p = enq(node);int ws = p.waitStatus;if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))LockSupport.unpark(node.thread);return true;}需要注意的是,調用該方法的前置條件是當前線程必須獲得了鎖,可以看到 Signal() 方法進行了 isHeldExclusively 檢查,判斷是否獲得了鎖,接著獲取等待隊列的首節點,將其移動到同步隊列并使用 LockSupport 喚醒節點中的線程。
節點從等待隊列,移動到同步隊列的操作過程如下:
通過調用同步器的 enq(Node node) 方法,等待隊列中的頭節點線程安全地移動到同步隊列中,當節點移動到同步隊列后,當前線程再使用 LockSupport 喚醒該節點的線程。
被喚醒的線程,將從 await() 方法中的 while 循環中退出。從 await 方法看
// 當前節點已經在同步隊列了,不會在循環下去了while (!isOnSyncQueue(node)) {LockSupport.park(this);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}隨后調用同步器的 acquireQueued() 方法加入到同步隊列的競爭中。
final boolean acquireQueued(final Node node, int arg) {boolean failed = true;try {boolean interrupted = false;for (;;) {final Node p = node.predecessor();if (p == head && tryAcquire(arg)) {setHead(node);p.next = null; // help GCfailed = false;return interrupted;}if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())interrupted = true;}} finally {if (failed)cancelAcquire(node);}}成功獲取同步狀態(獲得鎖)之后,被喚醒的線程,景從先前調用的 await 方法返回。此時線程已經成功獲得了鎖。
總結
本文剖析了一下 Condition 的實現原理,等待隊列,等待,通知的實現原理。
程序員開發者社區
總結
以上是生活随笔為你收集整理的实现原理_Condition 实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前馈pid系数_SPMSM控制——基于模
- 下一篇: python2 x与python3 x_