I.はじめに
最初ReentrantLockのを分析するものではなく、最終的な分析では、LockSuportのサポートなしで、そう単純そう最初に、それはロックの基本であるため、ロック機構は、ツールのプロバイダーである、最初の分析LockSupportに開始することを発見分析。
二、LockSupportソースコード解析
クラスの2.1プロパティ
LockSupportクラス{公共の ホットスポットは、APIを介して利用可能である組み込み関数の//実装 プライベート静的最終sun.misc.Unsafe UNSAFE; //オフセットアドレスメモリが表す プライベートロング決勝静的parkBlockerOffset; //オフセットアドレスメモリが表す プライベートロング静的最終SEED; //が表しますメモリオフセットアドレス プライベートロングPROBEファイナル静的; //オフセットアドレスメモリは表し SECONDARY決勝静的にプライベートロングを、 静的{ 試み{ //安全でない例ゲット UNSAFE sun.misc.Unsafe.getUnsafeを=(); //スレッドクラスタイプの クラスTK = Thread.class <?>; //スレッドparkBlockerのメモリオフセットアドレスフィールドを取得 parkBlockerOffset = UNSAFE.objectFieldOffset (tk.getDeclaredField( "parkBlockerは")); //スレッドを取得することは、フィールドメモリアドレスにオフセットthreadLocalRandomSeed SEEDを= UNSAFE.objectFieldOffset (tk.getDeclaredField( "threadLocalRandomSeed")); //スレッドthreadLocalRandomProbeを取得しますメモリオフセットアドレスフィールド PROBE = UNSAFE.objectFieldOffset (tk.getDeclaredField( "threadLocalRandomProbe")); メモリオフセットアドレススレッドフィールドがthreadLocalRandomSecondarySeed //取得 SECONDARY = UNSAFE.objectFieldOffset (tk.getDeclaredField( "threadLocalRandomSecondarySeed")); }キャッチ(例外例){スロー新しいエラー(EX);} } }
説明:UNSAFEフィールドはsun.misc.Unsafeクラスを表し、そのソースを表示は、こちらをクリックし、一般的なプログラムは、直接通話を可能にし、long型のフィールドを示していないメモリ内のオフセットアドレスを対応するオブジェクトの例は、によって相殺できます取得またはアドレスフィールドの値を設定します。
2.2クラスのコンストラクタ
//プライベートコンストラクタは、インスタンス化できない (){}プライベートLockSupportを
説明:LockSupportだけプライベートコンストラクタはインスタンス化できません。
2.3コア機能解析
コア機能はLockSupport公園・クラスで定義されunparkを安全でない機能をベースとしているので、解析LockSupport機能の前に、導入された最初のクラスsun.misc.Unsafe公園unparkを機能は、以下に示す2つの関数を定義します。
公共のネイティブの空の公園(ブーリアンisAbsolute、長い時間)。 公共のネイティブのボイドunparkを(スレッドthread);
説明:次の2つの関数の説明
①公園の機能、スレッドをブロックし、イベントの前にスレッドは、次のブロックされます:①unparkを機能、スレッドを解放する許可を呼び出します。②スレッドが中断されました。集合時間に③。そして、時間が絶対時間であるとき、isAbsoluteが真である、そうでない場合は、isAbsoluteはfalseです。時間が0である場合にはunparkをが発生するまで無限に待機を指示。
②unparkを機能、公園の呼び出しを有効にしているスレッドをブロックした後、スレッドを解放する許可。この関数は、この関数はスレッドがまだ生きていることを確認するために呼ばれ、安全ではありません。
1.パーク機能
過負荷パーク関数は、2つのバージョンがあり、この方法は、以下に要約しました
公共の静的な無効公園(); 公共の静的な無効公園(オブジェクトのブロッカー);
説明:二つの機能の間の差は、パーク()関数、すなわちスレッドがparkBlockerフィールドが設けられておらず、遮断しないことです。公園(Object)を以下のように関数を入力します。
静的な無効パークパブリック(オブジェクトのブロッカー){ //現在のスレッドを取得する スレッドにThread.currentThread = T(); //セットブロッカー setBlocker(T、ブロッカー); //取得ライセンス (falseに、0L)UNSAFE.park; //再この設定は、ブロッカー後に実行することができる setBlocker(T、NULL); }
説明:あなたは公園の関数を呼び出し、最初に現在のスレッドを取得した後、後に、呼び出しsetBlocker機能、安全でないクラスの公園の関数を呼び出した後、setBlocker関数を呼び出す設定parkBlockerフィールド現在のスレッド。質問があるので、なぜこの公園の機能は、二回setBlocker関数と呼ばれる必要がありますか?その理由は、あなたが公園の関数を呼び出す簡単な、現在のスレッド最初のセットのparkBlockerフィールド、その後、公園の機能安全でないを呼び出し、現在のスレッドはスレッドのunparkを関数が呼び出される待って、ブロックされた後、そのsetBlocker機能のバックです実行することはできません、unparkを関数が呼び出され、スレッド許可した後、あなたは実行し続けることができ、スレッドに二setBlocker、parkBlockerフィールドが実行されますので、公園全体の論理機能を完了、nullです。そこには、その後ノーコールパーク(オブジェクトのブロッカー)後の第二setBlocker、および直接呼び出しgetBlocker機能はありません、または公園(オブジェクトのブロッカー)セットの前にブロッカーを取得した場合、明らかに非論理的です。要するに、我々はスレッドparkBlockerフィールドの実装後の全体の機能公園(オブジェクトのブロッカー)はnullに戻ったことを確認する必要があります。だから、setBlockerの公園(オブジェクト)タイプの関数は、関数を2回呼び出す必要があります。setBlockerは次のとおりです。
静的ボイドsetBlockerプライベート(スレッドT、オブジェクトのarg){ //セットスレッドT引数parkBlockerフィールドである UNSAFE.putObject(T、parkBlockerOffset、引数); }
説明:このメソッドは、スレッドtのparkBlockerフィールドが引数で設定します。
次のようにパラメータを持たない別のオーバーロードされたバージョンは、公園()関数です。
静的ボイドパークパブリック(){ //は、ライセンスを取得し、時間を設定することは無限大であり、ライセンスがまで取得することができる UNSAFE.park(falseに、0L); }
説明:現在のスレッドが、しない限り、許可が利用可能になったとき、公園の関数を呼び出した後に無効になっています。次の条件が発生したときの3つのうちの1つが発生し、現在のスレッドが休眠状態になり、それが、ある前に、現在のスレッドがライセンスを取得します、あなたは実行し続けることができます。
①他のスレッドターゲット呼び出しunparkを現在のスレッド。
②他のスレッドが現在のスレッドに割り込み。
誤っ③コール(理由もなく)復帰します。
2. parkNanos機能
この関数は、現在のスレッド許可が指定された待機時間までのため、提供されています無効にします。具体的な機能は次の通り。
静的ボイドparkNanos公開(オブジェクトブロッカー、またはnanosのロング){ IFは(nanos値の> 0){//時間が0より大きい //現在のスレッドを取得する スレッドにThread.currentThread = T(); //設定ブロッカー setBlocker(T、ブロッカー); / /ライセンス、および設定時間得 ;(falseに、またはnanosの)UNSAFE.park //設定許可 setBlocker(T、NULL); } }を
説明:この関数は、二回setBlocker関数と呼ばれ、またはnanos相対時間を表すパラメータを待つために期間を示します。
3. parkUntil機能
パーミットが利用可能でない場合、この関数は、指定された期限まで、現在のスレッドを無効にします。具体的な機能は次の通り。
静的な無効parkUntilのパブリック(オブジェクトのブロッカー、ロングDEADLINE){ //現在のスレッドを取得する スレッドにThread.currentThread = T(); //セットブロッカー setBlocker(T、ブロッカー); UNSAFE.park(真、DEADLINEまで); //セットブロッカーヌルである setBlockerは(T、NULL); }
説明:この関数はまた、二回setBlocker関数と呼ばれ、期限パラメータは、絶対時刻を表すには、指定された時間を表します。
4. unparkを機能
指定されたスレッドの許可が使用できない場合は、それを利用できるようにするというこの機能は手段。スレッドが公園にブロックされた場合、それは状態のブロックを解除します。それ以外の場合は、公園への次の呼び出しはブロックするように保証するものではありません。指定されたスレッドが開始されていない場合は、この操作は効果がありませんことを保証することはできません。具体的な機能は次の通り。
unparkをパブリック(スレッドthread)への静的ボイド{ (!スレッド= null)のIF //スレッドが空ではありません UNSAFE.unpark(スレッド); //パーミッションは、スレッドを解放します }
説明:リリースのライセンスは、指定されたスレッドが実行を継続することができます。
第三に、例えば、ショー
2つのスレッドの同期を達成するために3.1
1.待機/通知実装
パッケージcom.hust.grid.leesf.locksupport。 クラスMyThreadは、Thread {拡張し ます。public void実行(){ 同期(本){ System.out.printlnは( "の前に通知を"); 通知()。 System.out.println( "の後に通知"); } } } publicクラスWaitAndNotifyDemo { 公共の静的な無効メイン(文字列[]引数)はInterruptedExceptionある{スロー MyThread myThread =新しいMyThreadの(); 同期(myThread){ 試み{ myThread.start()。 //主线程睡眠3S のThread.sleep(3000); System.out.println( "前の待機"); //阻塞主线程 myThread.wait(); System.out.println( "待ちの後に"); }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } } } }
業績
待機の前に 前に通知 を通知した後 、待機した後、
説明:特定のフロー図
待機を使用している場合/同期を通知し、あなたが最初の呼び出し待ちを行う必要があり、通知呼び出した後、最初の呼び出しがない場合は効果に、コール待機、通知します。次のように特定のコード
パッケージcom.hust.grid.leesf.locksupport。 クラスMyThreadは、Thread {拡張し ます。public void実行(){ 同期(本){ System.out.printlnは( "の前に通知を"); 通知()。 System.out.println( "の後に通知"); } } } publicクラスWaitAndNotifyDemo { 公共の静的な無効メイン(文字列[]引数)はInterruptedExceptionある{スロー MyThread myThread =新しいMyThreadを()。 myThread.start(); //主线程睡眠3S のThread.sleep(3000); 同期(myThread){ 試み{ System.out.println( "前の待機"); //阻塞主线程 myThread.wait(); System.out.println( "待ちの後に"); }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } } } }
結果:
前知らせる 通知後の 待ち時間の前に
説明:待機を呼び出して、通知の最初の呼び出しのように、この時間は、メインスレッドは、常にブロックのままになります。
3.2公園/達成パーキング位置から外し
パッケージcom.hust.grid.leesf.entry。 輸入java.util.concurrent.locks.LockSupport; クラスMyThreadはスレッド{延び プライベートオブジェクトオブジェクトを、 公共MyThread(Objectオブジェクト){ this.object =オブジェクト。 } 公共ボイドラン(){ System.out.printlnは( "unparkを前"); {試す のThread.sleep(1000); }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } //获取ブロッカー するSystem.out.println( "ブロッカー情報" + LockSupport.getBlocker((スレッド)オブジェクト)); //释放许可 LockSupport.unpark((ねじ)オブジェクト); //休眠500msの、保证先执行公園中的setBlocker(Tは、null); {試みる のThread.sleep(500)。 }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } //再次获取ブロッカー のSystem.out.println( "ブロッカー情報" + LockSupport.getBlocker((スレッド)オブジェクト)); System.out.println( "unparkを後に"); } } publicクラスのテスト{ 公共の静的な無効メイン(文字列[] args){ MyThread myThread =新しいMyThread(にThread.currentThread())。 myThread.start(); System.out.println( "公園の前に"); //获取许可 LockSupport.park( "ParkAndUnparkDemo"); System.out.println( "公園の後に"); } }
結果:
公園の前に unparkを前に ブロッカー情報ParkAndUnparkDemo 公園後の ブロッカー情報ヌル unparkを後に
説明:このプログラムの最初の実行公園、そしてunparkを、同期を実行し、前とunparkをがgetBlockerと呼ばれた後、次の2つの結果を見ることができるが、これはある、同じではありません、そして2回目の呼び出しの結果はnullであるため、 unparkを呼び出しの後、そう呼がヌルgetBlocker秒である場合、setBlocker(T、NULL)関数でLock.park(オブジェクトブロッカー)機能を行います。
例では、公園を呼び出し、次にunparkをを呼び出して、今のプログラムを修正し、最初の呼び出しのunparkを、その後、公園を呼び出して、あなたが正しく同期できるかどうかを確認することです。次のように特定のコード
パッケージcom.hust.grid.leesf.locksupport。 輸入java.util.concurrent.locks.LockSupport; クラスMyThreadはスレッド{延び プライベートオブジェクトオブジェクトを、 公共MyThread(Objectオブジェクト){ this.object =オブジェクト。 } 公共ボイドラン(){ System.out.printlnは( "unparkを前"); //释放许可 LockSupport.unpark((スレッド)オブジェクト); System.out.println( "unparkを後に"); } } publicクラスParkAndUnparkDemo { パブリック静的無効メイン(文字列[] args){ MyThread myThread =新しいMyThread(にThread.currentThread())。 myThread.start(); {試します //主线程睡眠3S のThread.sleep(3000); }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } のSystem.out.println( "公園の前に")。 //获取许可 LockSupport.park( "ParkAndUnparkDemo"); System.out.println( "公園の後に"); } }
結果:
unparkを前 unparkをした後 、公園の前 の公園の後
注:あなたが適切に同期することができ、まだ、その後、公園を呼び出したときに、以前のコールunparkを見ることができ、待ち時間が原因ではない/不適切なために起因する閉塞を呼び出し通知。公園だから/待機に比べunparkを/より柔軟に通知します。
2.割り込み応答
次の例を参照してください。
パッケージcom.hust.grid.leesf.locksupport。 輸入java.util.concurrent.locks.LockSupport; クラスMyThreadはスレッド{延び プライベートオブジェクトオブジェクトを、 公共MyThread(Objectオブジェクト){ this.object =オブジェクト。 } ます。public void実行(){ System.out.printlnは( "割り込みの前に"); 試す{ //休眠3S のThread.sleep(3000); }キャッチ(InterruptedExceptionある電子){ e.printStackTrace(); } スレッドのスレッド=(スレッド)オブジェクト。 //中断线程 thread.interrupt(); System.out.println( "割り込みの後に"); } } publicクラスInterruptDemo { パブリック静的無効メイン(文字列[] args){ MyThread myThread =新しいMyThread(にThread.currentThread())。 myThread.start(); System.out.println( "公園の前に"); //获取许可 LockSupport.park( "ParkAndUnparkDemo"); System.out.println( "公園の後に"); } }
結果:
公園の前に 割り込み前に 割り込み後に 公園の後
注:あなたがメインスレッドは、割り込み信号myThreadスレッドを発行し、公園がブロックされたコールでは、メインスレッドが同じunparkをの役割割り込みこの時点で明確であること、この時間に実行し続けることを見ることができます
IVの概要
ロックおよびその他の基本的なスレッド同期クラスブロッキングプリミティブを作成するためのLockSupport。要するに、あなたはLockSupport.parkを呼び出すときに、現在のスレッドがLockSupport.unparkを呼び出すときに、スレッドがパラメータとして渡さ取得する許可を待たなければならないので、このスレッドは引き続き実行されたライセンスまで待つことを示します。