LinkedBlockingQueue学習

免責事項:この記事はブロガーオリジナル記事ですが、許可ブロガーなく再生してはなりません。https://blog.csdn.net/ko0491/article/details/90903428

LinkedBlockingQueue

達成するために、キューLinkedB排他ロックをブロック!OckingQueue

LinkedB lockingQueueリンクされたリストが一方向を使用して実装され、それはまた、2つ持っている
ノードを、最初と最後のノードを記憶するために使用し、記録するために使用0原子COUNT変数の初期値、そこである
キューエレメントの数。2 ReentrantLockの別の例は、それぞれ、一次要素を制御し、デキューのため
takeLockつのみのスレッドがキューの先頭から得ることができる要素を制御するために使用されるプロトンが、他のスレッドがなければならない
と同時にのみ制御、putLockを待ちますキューの末尾に要素を追加し、ロックを取得することができますスレッドがあり、他のスレッドがします
待たなければなりません。また、notEmptyとnotFull条件は、彼らがフィード格納するために使用される条件内部キュー持って、可変であり
、チームとチームが、これは実際に生産者、消費者のモデルであると、スレッドがブロックされています。

過渡ノードヘッド。

/ **

  • リンクリストのテール。
  • 不変:last.next == nullの
    * /
    プライベート過渡ノードの最後。

テイク、世論調査で開催/ **ロック 、など* /
//取る行い、ロック取得に必要な世論調査の他の操作
民間最終ReentrantLockのtakeLock =新しいReentrantLockのを( );

待機用/ **待ちキューは取る* /
//キューが空の場合、デキュー操作は、(例えばテイクなど)スレッドがキュー待ちの状態に置かれている行って
(民間最終条件notEmpty = takeLock.newCondition) ;

プット、提供などにより開催/ ** *ロック/
//ロックのオファー他の操作*取得するための適切な時間のために、置く行う
民間最終ReentrantLockのputLock =新しいReentrantLockのを( );

/ ** * /キューを待っプットの待機
キューがいっぱいの場合(たとえば、PUTなど)の操作糸71を実行するチームはこの状態のチームに置かれているに]、//は待機
)(民間最終条件notFull = putLock.newConditionを 。

/ **要素の現在の数* /
キュー要素の//現在の数
民間最終のAtomicIntegerカウント=新のAtomicInteger( );

呼び出しスレッドがTAK E EUE例LinkedBlockingQu上で実行されるときに、ポーリングする他の動作を取得する必要がある
唯一のスレッドがヘッドノードリストを操作できることを保証するために、TAKのeLockロック。状態変数として、また
調子になるよう、ロック状態管理メカニズムtakeLockを使用して、キューのメンテナンス内部notEmpty条件
待つ前に、信号方式notEmptyスレッドを呼び出して最初のtakeLockロックを取得しなければならない、そうでない場合は、スローされます
Illegaをアウト!MonitorStateException例外を。内部キューはライン状態、維持notEmpty
プロセスがロックtakeLock notEmptyを取得するスレッドを呼び出す方法が遮断される待機し、その後、
スレッドは条件notEmptyキューの内部に配置され、スレッドの呼び出しまで待機しますnotEmpty
信号方式。

あなたは、実行putLockプットを取得電子LinkedBlockingQu EUの上の他の操作の例を提供する必要がある
唯一のスレッドがエンド・ノードのリストを操作できることを保証するためにロックを。また、原因の条件に変数
notFull内の状態は、状態管理のロック機構putLockを使用してキューを維持し、そう呼んで
、それ以外の場合はスローされます、呼び出しが法とSIを待つnotFull前にGNアルスレッドは最初putLockロックを取得する必要があります
Illegaを!MonitorStateEx C eption例外。スレッドが適格であるときnotFull内部状態は、キューを保持
putLockが呼び出さロックする時間を取ることが呼び出し元のスレッドがブロックされ、notFullを待って、その後、スレッドがします
スレッドの呼び出しがあるまで待つように内部キューnotFull条件に置かれます信号の方法notFull。

コンストラクタ
LinkedBlockingQueue(){公共
この(Integer.MAX_VALUEの);
}
公共LinkedBlockingQueue(INT容量){
IF(容量<= 0)スローはIllegalArgumentException新しい新しい();
this.capacity =容量;
//ように、最初と最後のノードを初期化しますそれらは、センチネルノードを指し
;最後= =新しい新ヘッドノード(NULL)
}

//ノードの
静的クラスノード{
Eアイテム。

/**
 * One of:
 * - the real successor Node
 * - this Node, meaning the successor is head.next
 * - null, meaning there is no successor (this is the last node)
 */
Node<E> next;

Node(E x) { item = x; }

}

オファーadd操作が追加されます

パブリックブールの追加(E電子){
(募集(e)は)場合は
trueを返します。
それ以外
(「フルキュー」)新しいIllegalStateExceptionがスロー。
}

ブールのオファーを公開(E E){
//(1)空の要素がnullポインタ例外をスローします
(E == null)のIF
新しい新しいNullPointerExceptionが(スロー);
現在のキューがいっぱいになると//取らは、要素の中に削除されます、次いで偽に戻り、
最終カウント=のAtomicIntegerのthis.count; //現在の容量
//が満杯でない
IF(count.get()==容量)
偽に戻り;
//(3)新たなノードが排他ロックputLock取得するように構成されて
INT Cを-1 =、
ノードノード新しい新しい=ノード(E);
ReentrantLockのputLock = this.putLockの最終;
putLock.lock();
試み{
(4)//、例えば採鉱などが不満キューキューを進み、要素がカウントをインクリメント
(カウント場合。 GET()<容量){
//新しい要素の追加
エンキュー(ノード)
数+ 1 //カウンタをインクリメントします。
count.getAndIncrementは= C();
// 5新しい要素は、空き領域のうち、キューに存在する場合notFull内部キューのウェイクアップ条件、決定します。
//ためののawait操作notFullを呼び出す(例えば、とき実行方法とキューがいっぱいになっている置く)と、ブロックされた
キューが空になっているので、スレッドに事前にチームが目を覚ますことができますので、//スレッドを。
IF(C用+ 1 <容量)
notFull.signal();
}
}最後に{
//リリースロック6
//取得putLockロック解除は、最終的に行われなければならないロックを解除し、ここで留意すべき
//さえTためブロックすることができます最終的には、それが実行される、投げ。さらに他の呼がロック解除操作を置くので、
ブロックされたスレッドは、そのロックを獲得しなければならないように//
; putLock.unlock()
}
// 7。
(C == 0)IF
== Oで説明// Cコードを実行する少なくとも一つの元素、キューが存在する場合(6)ロック・キューを解放
// signalNotEmpty動作が、実行される要素がある
signalNotEmptyは();
// 8
リターンC> = 0;
}

/ **

  • キューの末尾にノードをリンクします。
  • @paramノードノード
    * /
    プライベートボイドエンキュー(ノードノード){
    //)(putLock.isHeldByCurrentThreadをアサート。
    // last.nextを主張== nullを。
    最後= last.next =ノード。
    }

signalNotEmpty

プライベートボイドsignalNotEmpty(){
最終ReentrantLockのtakeLock = this.takeLock。
takeLock.lock();
{試みる
notEmpty.signal()。
}最後に{
takeLock.unlock()。
}
}

(比notEmptyを待って起動するので、この方法の効果は、notEmpty条件キューを活性化することで
も、呼び出し状態変数を示しスレッド、例えばテイク方法とキューを呼び出すように、空のとき)、およびブロック
対応を取得する前に方法をロック。

新しいキューテール原子のプロパティで操作ロック要素を確実にするための方法を使用してputLockプラン。さらに、
前者の方法は、対応するロックを取得することを忘れないでください、とチームは指摘したときにのみ、キューリストにエンドノードを操作しなければならない条件変数と呼ばれています。

置く操作
ます。public voidプット(E e)はInterruptedExceptionある{スロー
//(1)如果为空元素则抛出空指针异常
場合(E == nullの)スロー新しいNullPointerExceptionが();
//注:すべてのPUTで大会/取りますローカルの/ etc VARプリセットすることである
。//ない限りセット失敗を示すために負のカウントを保持する
。INT C = -1
ノードノード=新しいノード(E)は、
(2)构建新节点、并//获取独占19 \ putLock
最終ReentrantLockのをputLock = this.putLock;
最終のAtomicIntegerカウント= this.count;
putLock.lockInterruptibly();
{しようと
/ *
*それがされていても、そのカウントが待機ガードに使用されます
。*ロックで保護されていないがこれは、カウントすることができます動作します
*のみこの時点で減少(他のすべてのプットが閉じています
ロックOUT *)により、およびWE(またはいくつかの他の待機PUT)がされている
ITは、今までの容量から変化した場合*合図をした。同様に
*待機ガードでCOUNTの他のすべての他の用途のために。
* /
//(3)キューがいっぱいの場合、ブロッキング入るのを待って
いる間に(count.get()==容量){
notFull.await();
}
//最後の要素に追加
//(4)キューへとインクリメント
エンキュー(ノード);
//インクリメントカウンタ。1
C = count.getAndIncrement();
(C用+ 1 <容量)IF
//不満は、追加し続けることができ、ウェイク
notFull.signalを();
}最後に{
//ロック解除
putLock.unlockを();
}
IF(C == 0)
//ウェイクアップ
; signalNotEmptyを()
}

使用putLock.locklntenuptiblyコード(2)()を取得オファープロセスに比べ、排他ロックがかかり
、この方法は、中断することができる排他的ロック方式。具体的に現在のスレッドは、それがされている場合、ロックを取得する処理である
ので、操作取得に入れて、彼のスレッド割り込みフラグがセットされ、その後、現在のスレッドがIntenuptedException例外をスローする
プロセスのロックである中断することができます

コード(3)現在のキューが既にいっぱいであるかどうかを判断するために、notFullは電流にスレッドの呼び出し()メソッドで待つ
現在のスレッドが保留解放putLockがロックを獲得ブロックされた後、キューnotFullの条件。putLockロックがあるので
解放され、今、他のスレッドはロックputLockを獲得する機会を持っています

コードは(3)なぜキューではなくif文よりも空であるかどうかを決定する際にwhileループを使用できますか?これを考慮し
、現在のスレッドスプリアスウェイクアップ問題であること、つまり、他のスレッドはnotFull。方法notFullの葛呼び出しない
のawait()が自動的に特定の条件下で返します。if文誤ったウェークアップは、その要素のコード(4)を実行する場合
プライムエンキュー操作、およびカウンタをインクリメントするが、この時間は、キューは、それによって、キュー要素の数キューよりも大きい場合、その結果、既に満杯である
プログラムにつながる、容量が設けられていますエラーが発生しました。whileループを使用しているときnotFull.await()が目覚め偽であれば、
それは再び待機している場合、現在のキューをチェックするために、再びループが、すでにいっぱいです。

ポーリング操作が
キューの先頭から取得され、キューが空のヌル戻される場合要素を削除し、処理がブロックされていない
パブリックEポーリングを(){
//現在の容量の大きさを取得
=のAtomicIntegerのthis.count最終カウントを;
//( L)キューが空であるか、またはnullを返し
IF(count.get()== 0)
リターンヌル;
//(2)排他ロック
E X = NULL;
INT C = -1。

final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
    //(3 )队列不空则出队并递减计数
    if (count.get() > 0) {
        //出队列
        x = dequeue();
        //减一,计数器
        c = count.getAndDecrement();
        if (c > 1)
        //4  唤醒 线程,告诉线程,当前队列不是空
            notEmpty.signal();
    }
} finally {
    //解锁 5
    takeLock.unlock();
}
//移除之后,有一个空从头再来
if (c == capacity)
//唤醒 6
    signalNotFull();
return x;

}

デキュー
プライベートEデキュー(){
//主張takeLock.isHeldByCurrentThread();
// head.itemを主張== nullを。
ノードH =ヘッド。
ノード最初= h.next。
h.next = H; //ヘルプGCの
ヘッド=最初;
E、X = first.item。
first.item = NULL;
Xを返します。
}

プライベートボイドsignalNotFull(){
最終ReentrantLockのputLock = this.putLock。
putLock.lock();
{試みる
notFull.signal()。
}最後に{
putLock.unlock()。
}
}

コードは、(1)現在のキューが空である場合、プロセスは直接nullを返す判定する。
コードの後に(2)排他ロックtakeLock、ロックを獲得するために、現在のスレッド、ポーリングを呼び出す他のスレッドを取得したり
ハングアップが方法を取るブロックされます。

コードは、(3)現在のキューが空でデキュー操作ではないかどうかを決定するために行われ、その後、カウンタがデクリメントされます。考えるべき
、テストする方法キューは、3.1空でないとき、コードが実行されていることを確認するために、コードの実行がときに3.2空ではありませんか?結局のところ、これはない
アトミック操作、コードは、キューが空でないかを決定するために3.1を表示されますが、キューが空の場合3.2は、コードを実行するために?
その後、我々は前に3.2へのコードの実行をカウントし、カウントを変更しますする領域を見てください。現在のスレッドに持っている原因
takeLockロックを、その投票を呼び出すか、カウントするように来る回数を変更することはできません、他の方法でスレッドを取る
パーティーを。実際には、この時点では、他のスレッドの呼び出しを入れて運用ますので、カウントは、場所をカウントするために行った変更することができた場合に
二つの操作がtakeLockロックを取得する必要がないためputLockロックを取得しますが、操作に入れて提供される
内部カウントが増加していますカウント、上記のような状況は発生しません。実際には、単に領域が手渡さ何を見て
、カウント値に数を減らし、カウントがデクリメントされ、カウント値は3.1にする場合、コードの実行キューは、言ったの上に表示され
、空ではなく、コードの実行キューが空であるときの状況3.2。私たちは取るか、削除、唯一の世論調査では、コードを見て
カウント値がデクリメントされ、カウントのローカル操作を、これらの三つの方法で動作するtakeLockロックを取得する必要がありますが、
他のスレッドがチャンスを持っていないので、現在のスレッドがtakeLockロックを取得しています現在のカウントダウンカウント「のケースでは
値、コードは3.1のように見える、3.2はアトミックではありませんが、スレッドセーフです

コード(4)決意場合。Lキューが空でない待ち行列から要素を除去した後、現在のスレッド
C Cが要素を削除する前に、キュー内の要素の数である)、呼び出しがメソッドにブロックされているため、あなたが取ることができる。この時間は活性化された
内部notEmpty条件キュースレッド

コードは(6)キューの先頭の前に現在のチームの要素を削除するには、現在のスレッドの説明は、キュー内の現在のヘッド要素を除去した後、フルである
少なくとも1つの遊離の位置、コールが置かれているので、我々はS igna!NotFull活性化メソッドを呼び出すことができ、この時間を持っています抵抗
条件キューは、notFullのスレッドを詰め

投票コード・ロジックは、キューヘッドノードの動作のみが要素を取り出すときにことは注目に値する、比較的簡単です。

PEEK操作

キュー要素の頭部を取得しかし、キューが空の場合、nullを返し、キュー内からは削除されません。この方法はされていない
ブロックされた
パブリックPEEKのE(){
//容量サイズを取得1
IF(count.get()== 0)
リターンヌル;
// 2は、ロック取得
ReentrantLockの= this.takeLockの最終takeLockと、
takeLock.lock() ;
試み{

    Node<E> first = head.next;
    //3 
    if (first == null)
        return null;
    else
    //4 
        return first.item;
} finally {
    // 5
    takeLock.unlock();
}

}

コードここで、tもみを決定する必要(3)
かヌル、直接コードを実行することができない(通常のコードを実行中。。>説明キューが空ではなく、
コードCL)(2)また、アトミック操作ではないとキューが空ではない、(1)分析実行の時点でのコード(2)
取得可能前部ラッチ又は他のスレッドがポーリング動作を取るは、キューが空になることを引き起こします。現在のスレッドの対象が、その後されている
ロック後に撮影され、直接実行コード(4)(first.item)は、nullポインタ例外をスローします。

操作は取る-割り込み
キューの現在の先頭を取得し、内部のキューの要素から削除します。キューがするまでキューが現在のスレッド空のブロックである場合は
空ではない、その後、ブロッキングが設定されている場合は、割り込みフラグ他のスレッドがブロックされたとき、スレッドがスローされます、要素を返す
I n個のn terruptedExceptio異常リターンを

E)は(公共テイクInterruptedExceptionある{スロー
E Xは、
int型のC = -1;
//現在の容量を取得
決勝COUNT =のAtomicIntegerのthis.count;
//ロック1獲得
ReentrantLockの= this.takeLockの最終takeLockを、
takeLock.lockInterruptiblyを();
試してみます{
//(2)現在のキューをブロッキングプル空である
一方(count.get()== 0){
notEmpty.await();
}
//出力キュー(3)とカウントデキュー
X =デキュー() ;
//保存から算出
C = count.getAndDecrement();
// 4
IF(C> 1)
notEmpty.signal();
}最後に{
//ロック解除5。
takeLock.unlock();
}
// 6。
IF(容量== C)
signalNotFull();
戻りX;
}

コード(1)において、現在のスレッドが排他ロックを取得し、またはその他の呼び出しスレッドのポーリング動作をする取る
ペンディング遮断します。
キューが現在のスレッドが保留中のブロックされ、そしてnotEmptyストリップに現在のスレッド空である場合、コード(2)を決定する
メンバーキュー。
コード(3)およびデキュー操作をカウントします。
コードは、(4)現在のキューが空でない場合、C> L、notEmptyキュー次にウェイクアップ条件を判断
ためブロックされたスレッドの動作を取るための呼び出しを。
コード(5)ロックを解除します。
それは現在のキューを示す場合、コード(6)C ==容量決意は、少なくとも1つのアイドル位置、起動バー有する
操作を置くコールは、スレッドをブロックされているため、キュー内の可変条件notFull部材。

  1. reomove()操作は中断できない
    パブリックブールの削除(オブジェクトOを){
    falseに空を返す//
    IF falseに(O == null)のリターン;
    。。//ゲットロック1 -ダブルロック
    fullyLock();
    試み{
    // 2検索及び真に戻り、削除キューを横断
    するための(=ノードTRAILヘッド、P = trail.next;
    P = NULL ;!
    TRAIL = P、Pが= p.next){
    // 3
    IF(o.equals(p.item )){
    リンク解除(P、TRAIL);
    真に戻る;
    }
    }
    //見つからない場合は4 SE III押しFALの
    偽に戻り;
    }最後に{
    //ロック解除5
    fullyUnlock();
    }
    }

双重锁
ボイドfullyLock(){
putLock.lock()。
takeLock.lock();
}
ボイドfullyUnlock(){
takeLock.unlock()。
putLock.unlock();
}

コードは、(1)HyLockとして二重ロックが取得した、取得した後、他のスレッドは、エンキューまたはデキュー操作が「になる
ペンディング遮断します。

コードは(2)、削除したい要素を見つけるために、その後、偽の直接のリターンを見つけることができなかった、操作が実行されるリンク解除見つけキューをトラバース
(Pノード、ノードTRAIL){のボイドはunlinkを
//がアサートを(isFullyLocked);
// p.nextは変更されません、されている許可イテレータに
//が自分の弱P一貫性保証を維持するために横断。
p.item = NULL;
trail.next = p.next;
IF(最終==のP)
最終= TRAIL;
//現在のキューがいっぱいになった場合には、削除後、スレッドを待って目を覚ますことを忘れないでください
IF(count.getAndDecrement()==容量)
notFull.signal();
}

私たちが発見した場合の要素を除去した後、現在のキューは、自由空間、通話中にウェイクアップ状態のキューnotFullブロックされたスレッドのためのメソッドを置くために持っている
コード(5)とメソッド呼び出しをロックするには、ダブルリバースロックを解除するためにfullyUnlock

removeメソッドに加えて、特定のドルが見つけるためにキューを歩くにおけるので、指定された要素を削除する前に、2つのロックに
スレッドセーフの過程で素数である、そしてチームに呼び出すために、この時点で他のチームは、すべてのスレッドがブロックされます操作しました。また、
リソースのロック解除を複数取得し、順番が逆になります

サイズ操作
公共int型のサイズ(){
戻りcount.get()。
}

チームの結果、チームがロックを追加した場合の動作をカウントするので、ConcurrentLinkedQueue結果を比較
サイズメソッドは比較的正確です。

おすすめ

転載: blog.csdn.net/ko0491/article/details/90903428