正確にどのように不公平なReentrantLockの不公平ロック

リエントラントロックキーエリア:

1:状態「原子プラス1」の操作の安全でない方法AQS CASメンバ変数の使用。

2次の場合の動作状態に相当する現在のスレッドを繰り返しロックは、元の値に基づいて増加し続け、ロック状態を解除すると、「原子マイナス1」に達するがゼロです。

3:非ロックの問題でReentrantLockの株式:

スレッドは、スレッドノードリストにロックを取得していないときに厳密に、完全に不公平ではないに言えば、および状況下で複数のノードを持つリストがまだキュー公園に持って、継続してパーキング位置から外した後行くためにリストを待っているパイオニアノード。

株主資本は最初の試みは、最初の試みが失敗した場合、後にリストを待っ無視スレッドを行っていないときに、現在のロックが解除された場合、それは、ロックが解除されたか否かを判断しようとするロックされているのではなく、まだ無視したときに、2回の試行はロックされてリストを待っている他のスレッドは、直接足かせをしようとします。

4:hasQueuedPredecessors方法で公正なロックに焦点を当て:
(1)リストが作成されていない場合は、直接リソースのロックしよう;
(2)リストのヘッドノードの次のノードがnull、直接ロックしようと(実際に現在ある場合スレッド再進入);
(3)ロックを保持している現在のスレッドとスレッドは、同じスレッドだけでなく、直接ロック(実際には、現在のスレッドの再エントリ)である場合。

 公共の 最後の ブールhasQueuedPredecessorsは(){
         // これは頭に依存の正しさは、初期化される
         // 尾前と現在の場合head.nextが正確であることに
         // スレッドがキューの最初にあります。
        ノードT =尾。// 逆初期化順序で読み出しフィールド 
        ノードH = ヘッド。
        ノードs; 
        戻り!H = T && 
            ((S = h.next)== NULL!|| s.thread = にThread.currentThread())。
    }

PS:リストは、ヘッドノードのいずれかのノードロックを保持し、いずれかのトレッドデータフィールドは、ヌル・ノード比較的巧妙なデザインです。現在のリソースで初めて待機リストにロックされていないので最初のロックが終了すると、仮想の「代替ノード」のうち、著者は、それがロックを保持しているので、真のノード「代替ノード」を削除しますヘッドノードリストになります。

 公共の 最後の ブールhasQueuedPredecessorsは(){
         // これは頭に依存の正しさは、初期化される
         // 尾前と現在の場合head.nextが正確であることに
         // スレッドがキューの最初にあります。
        ノードT =尾。// 逆初期化順序で読み出しフィールド 
        ノードH = ヘッド。
        ノードs; 
        リターン!H = T &&
         // 下面这句话、实际就是当前线程重入 
            ((S = h.next)== nullを!|| s.thread = にThread.currentThread()); 
    }

5:待機リストのプロセスがロックされた後:

チームへのノードは、この方法は、ノードオブジェクトを返すとき、
(1)は、それが現在のノードが最初のノードである前にロックされたら、その後、現在のスレッドはすぐに試す発見された場合、ヘッドノードのアクティブパーキング位置から外しを待たずに、当然のことながら、ノードを率いますロックは、信号前のノードの状態かどうかを判断するために失敗した場合、現在のスレッドの状態は、ウェイクパイオニアノードを待って、自分の公園で遮断される場合には、パーキング位置から外しなります。ノードは、パイオニアの信号が、キャンセルされない場合は、信号がノードの背面に自分自身をリンクします見つけるまで、リンクリストに沿って楽しみにしています。

 最終的な ブール acquireQueued(最終ノードノード、INT のarg){
         ブール失敗= 試す{
             ブール中断された= ;
            (;;){
                 最終ノードp = node.predecessor()。
                もしP ==ヘッド && tryAcquire(引数)){ 
                    setHead(ノード)。
                    p.next = nullを// ヘルプGCが 
                    失敗した= ;
                    リターンは中断しました。
                } 
                であればshouldParkAfterFailedAcquire(P、ノード)&& 
                    parkAndCheckInterrupt() 
                    中断 = 
            } 
        } 最後に{
             場合(失敗)
                cancelAcquire(ノード)。
        } 
    }

ノードはヘッドノード前駆体でない場合(2)は、次に直接実行ロジックは中断されます。

プライベート 静的 ブールshouldParkAfterFailedAcquire(ノードは、ノードノード、predを){
         int型 WS = pred.waitStatus。
        もしWS == Node.SIGNAL/ * 
             *このノードには、リリースを求めてすでにセットのステータスを持っている
             、それが安全に駐車することができますので、それを合図します*。
             * / 
            戻る もしWSが> 0 ){
             / * 
             *前身はキャンセルされました。前任者の上にスキップして
             *再試行を示しています。
             * / 
            やる{ 
                node.prev= PRED = pred.prev。
            } 一方(pred.waitStatus> 0 )。
            pred.next = ノード。
        } {
             / * 
             * waitStatusは0またはPROPAGATEなければなりません。私たちがいることを示す
             *信号を必要とするが、まだ駐車しないでください。発信者は、にする必要があります
             確認してください、それは駐車場の前に取得することはできません作成する*再試行。
             * / 
            compareAndSetWaitStatus(predは、WS、Node.SIGNAL)。
        } 
        を返す 
    }

概要:
としては、1.6以前の同期キーワードはに比べて軽量ではないメカニズムReentrantLockのロッキング見ることができます。
一つのスレッドだけがロックされたときに、(1)資源消費の他のスレッドの状況、それは、待機中のリストを初期化しません唯一の非常に軽量CAS操作。
(2)繰り返しロック同じリソースのReentrantLockのサポート。
(3)キューがあっても、最初のスレッドノードオブジェクトを待っているキューは、ロックしようとするためのイニシアチブを取るでしょう。

おすすめ

転載: www.cnblogs.com/zzq-include/p/11995473.html