ロック嵌合インタフェース条件実現待機/通知モード、モニタとオブジェクトメソッド(のnotifyAll法等を、待機通知)は、待機/通知モードが実現されるが、この使用のモード、および機能の両方上の違いが残っています。
比較項目 | オブジェクトのモニター方法 | 調子 |
前置条件 | オブジェクトのロックを取得 | Lock.lockは()ロックを取得コール コールLock.newConditionは()条件オブジェクトを取得します。 |
呼ばれます | Object.wait():のような直接呼び出し、 | 以下のような直接呼び出し、:condition.await() |
待ち行列の数 | A | もっと |
現在のスレッドがロックを解除し、待機状態に入ります | サポート | サポート |
現在のスレッドは、ロックを解除し、待機状態に入ります 待機している状態では、割り込みに応答しません |
サポートしていません。 | サポート |
現在のスレッドがロックを解除し、タイムアウト待ち状態に入ります | サポート | サポート |
現在のサイトのロックを解除し、いくつかの将来の時間に待機状態に入るための | サポートしていません。 | サポート |
キュー内で待機しているスレッドを覚まします | サポート | サポート |
キュー内で待機中のすべてのスレッドを覚まします | サポート | サポート |
監視中のオブジェクトモデルは、オブジェクトは、同期キューおよび待機キューを持っており、AQSは、同期キューと待機している複数のキューを持っています。
オブジェクトの監視モデル:
キューの同期と待つキュー条件:
説明方法や条件セクション:
メソッド名 | 説明 |
空のawait()がスロー |
通知(信号)、または中断されるまで待ち状態に現在のスレッド、 現在のスレッドが実行状態に入り、(このメソッドが返すからショーを待つだろう スレッドがロックを、対応する条件オブジェクト)を含む、取得しています: 他のスレッドのコール(コール割り込み()メソッドは、現在のスレッドに割り込み) 信号の状態()またはsignalAll()メソッド、および現在のライン チェンはウェイクを選択しました |
awaitUninterruptiblyを無効() |
待ち状態に現在のスレッドが、通知されることを知って、小文字を区別しないが中断する |
長いawaitNanos(ロングnanosTimeoutは) |
待ち状態に現在のスレッドには、通知を受け、中断またはタイムアウトするまで、 戻り値は、残り時間を表しnanosTimeoutがあればナノ秒 前に目覚めされ、戻り値がある(nanosTimeout - 実際の時間がかかります)。 リターンがゼロまたは負の場合、それはタイムアウトしました。 |
ブールawaitUntil(日締め切り) |
中断された、またはAに待機状態に現在のスレッドそれが通知されるまで、 時間。特定の時間にない通知すべき、trueを返します。それ以外の場合は、 falseを返します |
無効信号() |
待機状態のスレッド、待機中のメソッドからのスレッドで目を覚まします 条件は、前者のリターンに関連したロックを取得する必要があります |
signalAllを無効() |
すべてのwaitメソッドからスレッドの状態にすることができます待って目覚めます 返されたスレッドは、条件に関連付けられているロックを取得する必要があります |
実現の条件
①待ち行列
同期キュースレッドへの参照を含むスレッドがCondition.await()メソッドを呼び出し、その後、スレッドが解放される場合、スレッドは、オブジェクトの状態のスレッドを待っているキュー内の各ノードの状態の前にキューを待ちます待ちキューノードは、待機状態に入るに参加するように、ロックします。同期キューおよびキューノードタイプを待つ内部クラスノードAQSに静的です。条件は、AQSの静的内部クラスです。
待つ②
待つメソッド呼び出しの状態は、待ちキューに現在のスレッドを作成して、ロックを解除しますが、スレッドの状態が状態を待つように。待つ方法からの復帰時に、現在のスレッドは、状態に関連するロックを獲得しなければなりません。
1 public final void await() throws InterruptedException { 2 if (Thread.interrupted()) 3 throw new InterruptedException(); 4 Node node = addConditionWaiter(); // 当前线程加入等待队列 5 int savedState = fullyRelease(node); // 释放同步状态,也就是释放锁 6 int interruptMode = 0; 7 while (!isOnSyncQueue(node)) { 8 LockSupport.park(this); 9 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) 10 break; 11 } 12 if (acquireQueued(node, savedState) && interruptMode != THROW_IE) 13 interruptMode = REINTERRUPT; 14 if (node.nextWaiter != null) // 线程被取消的话要清除节点 15 unlinkCancelledWaiters(); 16 if (interruptMode != 0) 17 reportInterruptAfterWait(interruptMode); 18 }
如果队列的角度来看await()方法,当调用await()方法时,相当于把同步队列的首节点(获取了锁的节点)移动到Condition的等待队列中,实际上是通过addConditionWaiter()方法把当前线程构造成一个新的节点并将其加入等待队列中。
③ 通知
调用该方法的前置条件是要获取了锁,方法首先用isHeldExclusively()检查,接着获取等待队列的首节点,将其移动到同步队列并使用LockSupport工具类唤醒节点中的线程。
1 public final void signal() { 2 if (!isHeldExclusively()) 3 throw new IllegalMonitorStateException(); 4 Node first = firstWaiter; 5 if (first != null) 6 doSignal(first); 7 }
1 private void doSignal(Node first) { 2 do { 3 if ( (firstWaiter = first.nextWaiter) == null) 4 lastWaiter = null; 5 first.nextWaiter = null; 6 } while (!transferForSignal(first) && 7 (first = firstWaiter) != null); 8 }
1 final boolean transferForSignal(Node node) { 2 /* 3 * 如果无法更改waitStatus,则该节点会被取消 4 */ 5 if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) 6 return false; 7 8 /* 9 * 拼接到队列上并尝试设置前任的waitStatus以指示线程(可能)正在等待。 10 * 如果取消或尝试设置waitStatus失败,请唤醒以重新同步 11 * (在这种情况下,waitStatus可能是暂时性且无害的错误) 12 */ 13 Node p = enq(node); 14 int ws = p.waitStatus; 15 if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) 16 LockSupport.unpark(node.thread); 17 return true; 18 }
节点从等待队列移动到同步队列: