1. ホーム
  2. java

[解決済み] ConcurrentLinkedQueueの使い方を教えてください。

2022-12-06 22:36:04

質問

どのように ConcurrentLinkedQueue をJavaで使うのですか?

これを使用して LinkedQueue を使用して、私はキューの並行性について心配する必要がありますか?それとも、2つのメソッド(リストから要素を取得するメソッドとリストに要素を追加するメソッド)を定義すればいいのでしょうか?

注:明らかにこれら2つのメソッドは同期されなければなりません。そうでしょうか?


EDITです。 私がやろうとしていることはこれです。私は、キューからアイテムを取得するための1つのメソッドを持つクラス(Java)と、キューにアイテムを追加するための1つのメソッドを持つ別のクラスを持っています。追加された項目とリストから取得された項目は、私自身のクラスのオブジェクトです。

もう1つの質問:私はremoveメソッドでこれを行う必要があります。

while (queue.size() == 0){ 
  wait(); 
  queue.poll();
}

コンシューマとプロデューサは1つずつしかありません。

どのように解決するのですか?

いいえ、メソッドを同期させる必要はありませんし、メソッドを定義する必要もありません。これらはすでに ConcurrentLinkedQueue に含まれているので、それを使用すればよいのです。ConcurrentLinkedQueue は、必要なロックやその他の操作をすべて内部で行います。プロデューサーがキューにデータを追加し、コンシューマーがそれをポーリングします。

まず、キューを作成します。

Queue<YourObject> queue = new ConcurrentLinkedQueue<YourObject>();

さて、producer/consumer オブジェクトを作成するときは、キューを渡してオブジェクトを置く場所を確保します (このためにセッターを使うこともできますが、私はこの種のことはコンストラクタで行う方が好きです)。

YourProducer producer = new YourProducer(queue);

とする。

YourConsumer consumer = new YourConsumer(queue);

を作成し、プロデューサーでそれに何かを追加します。

queue.offer(myObject);

で、コンシューマでいろいろ取り出します(キューが空の場合、poll()はnullを返すので、それをチェックします)。

YourObject myObject = queue.poll();

より詳しい情報は Javadocを参照してください。

EDITです。

キューが空にならないように待つブロックが必要な場合、おそらくは リンクドブロッキングキュー(LinkedBlockingQueue を使用し、take() メソッドを使用します。ただし、LinkedBlockingQueueには最大容量(デフォルトはInteger.MAX_VALUEで、20億以上)があるので、状況によって適切な場合とそうでない場合があります。

1 つのスレッドがキューにデータを入れ、別のスレッドがキューからデータを取り出すだけであれば、ConcurrentLinkedQueue はおそらく過剰な処理です。これは、何百、何千ものスレッドが同時にキューにアクセスするような場合に適しています。

あなたのニーズは、おそらく

を使用することによって満たされるでしょう。

Queue<YourObject> queue = Collections.synchronizedList(new LinkedList<YourObject>());

この利点は、インスタンス(キュー)をロックすることで、複合操作の原子性を保証するためにキュー上で同期することができます(Jaredが説明したとおりです)。すべての操作はインスタンスをロックせずに行われるため、ConcurrentLinkedQueueでこれを行うことはできません(java.util.concurrent.atomic変数を使用します)。キューが空の間は poll() は単に null を返し、 poll() はアトミックなので、キューが空の間にブロックしたい場合は、これを実行する必要はありません。poll() が null を返すかどうかを確認します。もしそうなら、wait()をして、もう一度試してください。ロックする必要はありません。

最後に

正直なところ、私はLinkedBlockingQueueを使うだけでいいと思います。あなたのアプリケーションにとってはまだ過剰ですが、うまくいく可能性は高いです。もし十分なパフォーマンスが得られない場合(PROFILE!)、いつでも他のものを試すことができますし、同期されたものに対処する必要がないことを意味します。

BlockingQueue<YourObject> queue = new LinkedBlockingQueue<YourObject>();

queue.put(myObject); // Blocks until queue isn't full.

YourObject myObject = queue.take(); // Blocks until queue isn't empty.

他はすべて同じです。置く おそらく はブロックしません。なぜなら、20億個のオブジェクトをキューに入れることはないでしょうから。