目次
ArrayBlockingQueueの実用的なアプリケーションシナリオ
ArrayBlockingQueueの簡略化されたクラス図構造
完全に非ブロッキングキューConcurrentLinkedQueue
マルチスレッドの安全スキームを一覧表示します:LinkedBlockingQueue
ArrayBlockingQueueの実用的なアプリケーションシナリオ
以前、会社で感情認識システムを行ったことがあります。このシステムは、カメラインターフェースを呼び出して顔情報を収集し、収集した顔情報に対して顔認識と感情分析を実行し、最終的に特定のアルゴリズムによって個人の感情データを特定の行動に変換します。インデックス値。並行キューArrayBlockingQueueは、画像の収集の一部で使用されます。
上図のように、カメラがn台あり、シングルスレッド収集の効率が遅いため、カメラ収集のプロセスがマルチスレッドになり、収集した画像を画像サーバーに保存する必要があります。 、およびピクチャーサーバーへの書き込みも非常に高くなります。イメージサーバーはクラスター化されている必要があり、マルチスレッドである必要もあります。画像をデータベースに保存した後、画像データを顔分析サーバーに送信して処理する必要があります。この部分には分散メッセージが含まれるため、黒い破線部分はkafkaを使用してメッセージを送信します。その中で、マルチスレッド画像コレクションの赤い点線部分は、マルチスレッド画像ストレージに情報を転送し、並行セーフキューであるArrayBlockingQueueを使用します。
ArrayBlockingQueueの簡略化されたクラス図構造
クラス図から、キューインターフェイスがキューに追加および提供するためのメソッドと、キューからポーリングするためのメソッドを提供していることがわかります。
BlockingQueueインターフェースは、キューにputメソッドを追加し、キューから取り出すメソッドを追加します。
補足説明:UMLクラス図の構造:
- 継承:実線と空の矢印。
- 実現:一点鎖線の矢印。
同時キューブロッキングと非ブロッキングの概念
上記のクラス図の名前から、Queueによって提供されるメソッドが非ブロッキングであることがわかります。BlockingQueueの提供PUTは、テイクメソッドがブロックされています!古いアイデアに従って、コードを使用してブロッキングと非ブロッキングを説明します。
ノンブロッキング
import java.util.concurrent.ArrayBlockingQueue;
/**
* @author :jiaolian
* @date :Created in 2021-02-02 20:16
* @description:ArrayBlockingQueue阻塞非阻塞测试
* @modified By:
* 公众号:叫练
*/
public class ArrayBlockingQueueTest {
public static void main(String[] args) {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
arrayBlockingQueue.offer("叫练");
arrayBlockingQueue.offer("叫练");
//输出arrayBlockingQueue的长度
System.out.println(arrayBlockingQueue.size());
}
}
上記のコード:ArrayBlockingQueueの長さを1に設定し、offerメソッドを使用してキューに2つの要素を追加し、最後にarrayBlockingQueueの長さを出力しますか?答えは1つで、ブロックされません。offerメソッドは「プラクティスと呼ばれる」2番目の要素を破棄するため、チームとチームは、非ブロックと呼ばれるキューを引き続き許可できると言います。addメソッドに置き換えられた場合はどうなりますか?次の図に示すように、キューがオーバーフローするというエラーが報告されます。しかし、それはまだブロックされていません。何がブロックされているか見てみましょう!
ブロック
import java.util.concurrent.ArrayBlockingQueue;
/**
* @author :jiaolian
* @date :Created in 2021-02-02 20:16
* @description:ArrayBlockingQueue阻塞非阻塞测试
* @modified By:
* 公众号:叫练
*/
public class ArrayBlockingQueueTest {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
arrayBlockingQueue.put("叫练");
arrayBlockingQueue.put("叫练");
//输出arrayBlockingQueue的长度
System.out.println(arrayBlockingQueue.size());
}
}
上記のコード:ArrayBlockingQueueの長さは1で、putメソッドを介して2つの要素がキューに追加されます。最終的な出力arrayBlockingQueueの長さはどれくらいですか。答えは、2番目の「呼び出し練習」が追加されるとプログラムがブロックされるため、コンソールは実行し続けるということです。私たちは、と言うチームとチームは、ブロックと呼ばれる私たちのキューを実装するために継続させることができない、あなたが最も簡単なテストを行うためのコードを書くことができます。一例により、我々はない一つの方法を取る、ポーリング方式を追加する方法を!
さて、いくつかの方法を要約しましょう!
- チームに参加する:
オファー:キューがいっぱいで破棄されます。
追加:キューがいっぱいで、エラーが報告されます。
置く:ブロッキング。
- 出発:
ポーリング:キューが空の場合、nullを返します。
取る:ブロッキング。
ArrayBlockingQueueの実現原理の分析
上の図に示すように、ArrayBlockingQueueは配列を使用して実装され、ReentrantLock排他ロックは配列のエンキューとデキューを制御します。notEmptyとnotFullは、ReentrantLockの2つの条件付きキューであり、キューがブロッキング状態になるかどうかを制御するために使用されます。これらは、プロデューサーモデルとコンシューマーモデルです。takeメソッドとputメソッドのプロセスを見てみましょう。他のメソッドも同じです。
- takeメソッド:複数のスレッドが排他ロックを競合してitems [ taskIndex ]キューの最初の要素を取得します。Aスレッドはロックを正常に取得し、他のスレッドはブロックして、Aスレッドの実行がロックの解放を完了するのを待ちます。キューが空でない場合、Aスレッドはitems [ taskIndex ]要素を取得します。Returnキーを押してロックを削除および解放し、他のブロックされたスレッドが引き続き競合できるようにします。キューが空の場合、スレッドAはnotEmpty.awaitメソッドを呼び出して条件付きキューとロックを解除して、他のブロックされたスレッドが引き続き競合できるようにします。他のスレッドも、キューが空であることがわかったときにnotEmpty条件付きキューに入り、putスレッドがキューに参加するのを待って、notEmptyに通知してスレッドをブロックします。 。
- putメソッド:複数のスレッドが排他的ロック設定項目をめぐって競合します[putIndex ]キューのテール要素。ここで、スレッドはロックを正常に取得し、他のスレッドはブロックし、キューがロックの解放を完了するまでスレッドの実行を待機します。いっぱいではない[キューの長さ]、スレッドはアイテムを追加します[ putIndex ]要素はロックを返し、ロックを解除して、他のブロックされたスレッドが引き続き競合できるようにします。キューがいっぱいの場合、スレッドAはnotFull.awaitメソッドを呼び出して条件付きキューに入ります。ロックを解放して、他のブロックされたスレッドが引き続き競合できるようにします。他のスレッドも、キューが空であることを検出すると、notFull条件付きキューに入ります。、takeスレッドがデキューするのを待って、notFullに通知してスレッドをブロックします。
完全に非ブロッキングキューConcurrentLinkedQueue
ConcurrentLinkedQueueは、キューインターフェイスも実装し、すべて非ブロッキングのオファー、追加、およびポーリングメソッドを提供します。さらに、名前からわかるように、最下層はリンクリスト構造であり、エンキューおよびデキューはスピンカスを使用します。 。
マルチスレッドの安全スキームを一覧表示します:LinkedBlockingQueue
LinkedBlockingQueueはArrayBlockingQueueに似ています。LinkedBlockingQueueは制限されており、長さはInteger.MAX_VALUEです。実装に関しては、LinkedBlockingQueueはリンクリストであり、ダブルロックされています。上の図に示すように、takeLockはキューの先頭を排他的に制御します。 putLockはキューの末尾を制御し、相互に影響を与えません。目的は、LinkedBlockingQueueの同時実行性を向上させることです。
総括する
本日は、コンカレントキューのいくつかの重要な概念を紹介しました。それらを整理して、お役に立てれば幸いです。書き込みが完了していません。同時に、修正が必要なことがたくさんあります。修正していただければ幸いです。コメント。これらの出力スレッドプールの概念など。好きなものに気をつけてください。注意してください、迷子にならないでください、私はリアン[公式アカウント]と呼ばれ、練習しながら電話をかけています。
参考書:「Java並行プログラミングの美しさ」