0

getQueue() メソッドは、ThreadPoolExecutor 内の基礎となるブロッキング キューへのアクセスを提供しますが、これは安全ではないようです。

この関数によって返されたキューをトラバーサルすると、ThreadPoolExecutor によってキューに対して行われた更新が失われる可能性があります。

「メソッド getQueue() を使用すると、監視とデバッグの目的で作業キューにアクセスできます。他の目的でこのメソッドを使用することは強くお勧めしません。」

ThreadPoolExecutor が使用する workQueue をトラバースしたい場合はどうしますか? または、代替アプローチはありますか?

これは、の続きです.. 生産者消費者問題のバリアントのデータ構造の選択

現在、複数のプロデューサーと複数のコンシューマーを試していますが、スレッドプールを自分で管理したくないため、既存のスレッドプールを使用したいと考えています。スレッドセーフな方法で、「進行中のトランザクション」データ構造。

4

3 に答える 3

1

キュー内のアイテムをコピーして、キュー内にあるものが実行されていないことを確認したい場合は、次のようにしてみてください。

a) 実行を一時停止および再開する機能を導入します。参照: http://download.oracle.com/javase/1,5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html

b) 最初にキューを一時停止し、次にキューをコピーしてから、キューを再開します。

そして、私は私自身の質問があります。私が見る問題は、「Runnable」を実行している間、その「Runnable」がキューに配置されず、FutureTask「ラッパー」に配置され、どのランナブルを探しているかを判断する方法が見つからないことですで。したがって、キューを取得して調べることはほとんど役に立ちません。私がそこを逃したことを知っている人はいますか?

于 2011-05-19T21:13:03.333 に答える
1

beforeExecute および afterExecute メソッドをオーバーライドして、タスクが開始および終了したことを知らせることができます。execute() をオーバーライドして、タスクがいつ追加されたかを知ることができます。

あなたが抱えている問題は、キューがクエリされるように設計されておらず、タスクが表示される前に消費される可能性があることです。これを回避する1つの方法は、キューの独自の実装を作成することです(おそらく、ConcurrentLinkedQueueをオーバーライド/ラップします)

ところで: キューはスレッドセーフですが、すべてのエントリが表示されるとは限りません。

ConcurrentLinkedQueue.iterator() は次のように文書化されています

このキュー内の要素に対する反復子を適切な順序で返します。返されたイテレータは、ConcurrentModificationException を決してスローしない「弱い一貫性のある」イテレータであり、イテレータの構築時に存在していた要素をトラバースすることを保証し、構築後の変更を反映する可能性があります (ただし保証はされません)。

于 2011-05-09T10:22:15.817 に答える
0

前の質問から受け入れられた回答で Jon Skeet のアドバイスに従っている場合は、ロックを介してキューへのアクセスを制御することになります。進行中のキューでロックを取得すると、トラバーサルがその中のアイテムを見逃さないことを保証できます。

もちろん、これに関する問題は、トラバースを実行している間、キュー上の他のすべての操作 (アクセスしようとしている他のプロデューサーとコンシューマー) がブロックされ、パフォーマンスにかなりの影響を与える可能性があることです。

于 2011-05-09T10:30:29.290 に答える