2011-12-18 15 views
0

正確な結果が必要な計算(CTR暗号化)があります。Java:非同期タスクから検索された結果の順序

私はこの結果を計算するマルチスレッド設計を作成しました。この場合、結果はByteBufferです。計算自体はもちろん非同期で実行されるため、結果はいつでも任意の順序で利用できるようになります。 「ユーザー」はメソッドを呼び出すことによって結果を使用する単一スレッドのアプリケーションであり、その後メソッドはByteBuffersをリソースプールに戻します。リソースの管理は既に(スレッドセーフスタックを使用して)処理されています。

質問:結果を集約し、の右注文で利用できるものが必要です。次の結果が利用できない場合は、ユーザーが呼び出すメソッドがブロックされるまでブロックする必要があります。誰かが順調に計算結果を非同期的に返すことができるjava.util.concurrentの良い戦略やクラスを知っていますか?

解決策はスレッドセーフでなければなりません。私はサードパーティ製のライブラリであるThread.sleep()/ Thread.wait()と、synchronized以外の関連キーワードを避けたいと思います。さらに、タスクは、例えば、それが必要な場合は、正しい順序でエグゼキュータを実行します。これは研究用ですので、Java 1.6または1.7のコンストラクトを自由に使用してください。

注:私はJREで定義されたクラスと[暗号化]の中で誰かがすでに対処していたかもしれないので、これらの質問[jre]にタグを付けましたが、質問自体は純粋にjava &マルチスレッド。

+0

なぜByteBuffer配列を作成し、Bytebufferをスレッドに渡すのはなぜですか?すべてのスレッドが完了したら、ByteBuffersを配列順に書き込みます。 – fge

+2

暗号化とは関係がないため、「暗号化」タグを削除しました。 –

答えて

4

executors frameworkを使用します。

ExecutorService executorService = Executors.newFixedThreadPool(5); 
List<Future> futures = executorService.invokeAll(listOfCallables); 
for (Future future : futures) { 
    //do something with future.get(); 
} 
executorService.shutdown(); 

listOfCallablesは、あなたがデータを操作するように構成しているList<Callable<ByteBuffer>>になります。たとえば、次のように

list.add(new SubTaskCalculator(1, 20)); 
list.add(new SubTaskCalculator(21, 40)); 
list.add(new SubTaskCalculator(41, 60)); 

(数字の任意の範囲、手元のタスクにそれを調整する)

.get()ブロック結果が完了しているが、同時に他のタスクも実行されているので、ときにされるまで、それらに達すると、彼らの.get()は準備が整います。

+0

私は最初の回答の1つになるのではないかと恐れていました(以前のStackOverflowでカバーされていたように)。残念なことに、ByteBuffersは使用後に使用可能になり、他のリソースが使用可能になると、次のタスクが起動されます。言い換えれば、私は同時にすべての仕事をすることはできません。 –

+0

+1を実行します。 @wlstead、私はあなたの返事を理解していません。 「使用後に利用可能になる」とはどういう意味ですか?実行中のタスクの数を一度に制限することができ(例のコードでは5に設定されています)、タスクが完了すると、すてきなことを行うCompletionServicesがあります。 – user949300

+0

私はそれも得られませんでした。あなたの次のタスクが前のタスクに依存する場合は、同期して実行します - 別のオプションはありません – Bozho

1

結果を正しい順序で返すことは簡単です。それぞれの結果が到着すると、それをarraylistに格納し、すべての結果を取得したら、arraylistを並べ替えます。 PriorityQueueを使用すると、到着時に常にソートされた結果を保持することができますが、結果が得られる前にすべてを使用することはないため、これを行う際には何の意味もありません。

だから、何あなたができることはこれです:彼らは序数でソートすることができるように

は、あなたのByteArrayとして定義し、その序数の1が含まれている「作業項目」クラスを宣言します。あなたの仕事のスレッドで

、このような何か:あなたのメインスレッドで

...do work and produce a work_item... 

synchronized(LockObject) 
{ 
    ResultList.Add(work_item); 
    number_of_results++; 
    LockObject.notifyAll(); 
} 

を、このような何か:あなたが何をしたいのより良い理解を得る後

synchronized(LockObject) 
    while(number_of_results != number_of_items) 
     LockObject.wait(); 
ResultList.Sort(); 
...go ahead and use the results... 
+0

ありがとうMikeNakis。しかし、私はできるだけ早く結果を利用可能にすることを考えています。そうしないと、その時に必要な結果以外の結果に対して計算が実行されている間、ユーザーはブロックします。 –

+0

OK、これは質問に指定されていません。したがって、呼び出し元が結果を生成するコードと並行して結果に取り組んでいるとし、次の結果が順番どおりに動作するようにしたいとしますが、まだ実行していない場合は待機しますか? –

+0

まさに!あなたはそれを持っています。 –

0

私の新しい答えをする:

バイト配列とその序数のいずれかを含む「WorkItem」クラスを宣言して、序数でソートできるようにします。

序数でソートされたjava.util.PriorityQueueを使用します。基本的には、優先キューの最初の項目は、常に処理する次の項目になります。

各作業スレッドは、その結果をPriorityQueueに格納し、一部のロックオブジェクトにNotifyAllを発行します。

ロックオブジェクトのメインスレッドを待機し、その後キュー内の項目がある場合、キューに(覗く、デキューしない)最初の項目の順序は、これまでの処理項目数に等しい場合アイテムをデキューして処理します。そうでなければ、それは待っている。すべての品目が生産され、処理された場合、それは完了です。

+0

これは非常に有望な答えのように聞こえる、ロックオブジェクトと優先順位キューの使用を調査します。 –

+0

私はいくつかのコードを試しましたが、キューに要素を配置する際の競合条件と、ロック対象と共に要素の覗き見/削除を実行し続けます。 –

+0

マルチスレッド化は容易ではありません。 PriorityQueueは同期されていないので、独自の同期を提供する必要があります。物事をロックするときやアクセスするときには、非常に注意する必要があります。 wait()に入る前に条件をチェックする必要があります。そうしないと、通知されることはありません。 wait()から起床しても、待機していた状態が発生したわけではないので、通常は条件が実際に成立するまでループする必要があります。それを解決できない場合は、人々が問題を見つけられるようにコードを投稿したいと思うかもしれません。 –

関連する問題