2013-04-04 12 views
9

現在のコードでは、結果が最高レベルになる一連の非同期プロセスが使用されています。私は、それぞれが結果を戻り値として持つ同期メソッドによってアクセスされるように、これらのそれぞれをラップする必要があります。私はこれを実行するためにエグゼクティブサービスを使用して、これらの多くが同時に発生するようにします。私は、未来が私の実装に関係するかもしれないという気持ちがありますが、これを実現させる良い方法を理解することはできません。これは、内部的にかなりうまく働いたが、今のような戻り値に同期する方法に私のプロセスをマッピングする必要があり戻り値のある同期メソッドで一連の非同期呼び出しをラップする

public class DoAJob { 
    ResultObject result; 

    public void stepOne() { 
    // Passes self in for a callback 
    otherComponent.doStepOne(this); 
    } 

    // Called back by otherComponent once it has completed doStepOne 
    public void stepTwo(IntermediateData d) { 
    otherComponent.doStepTwo(this, d); 
    } 

    // Called back by otherComponent once it has completed doStepTwo 
    public void stepThree(ResultObject resultFromOtherComponent) { 
    result = resultFromOtherComponent; 
    //Done with process 
    } 
} 

public ResultObject getResult(){ 
    // ??? What goes here ??? 
} 

は、誰にも何私が今持っている

これをエレガントに実装する方法については良いアイデアがありますか?

+1

この仕様には欠点が1つあります。最終的に、異なるタスクのResultObjectをどのように組み合わせて単一のものにする予定ですか? –

+0

私はその質問を理解しているか分からない。通常、プロセスは新しいDoAJob.stepOne()によって開始されます。 stepTwo()メソッドは、otherComponentからのコールバックによって開始されます。コールバックのチェーンの終わりに、ResultObjectが正しく挿入されます。中間データビットはすべて最終結果に統合されます。 – irondwill

答えて

0

。それはエグゼキュータに一連のタスクを提出し、最後のタスクが完了するまでブロックします(正常に/例外あり)。その後、完了したFutureオブジェクトのリストを返します。そのため、それらをループして結果を単一のResultObjectにマージすることができます。あなたに

では、次を使用することができ、同期的にのみ単一のタスクを実行したい:

executor.invokeAll(Collections.singleton(task)); 

--edit--

今、私は私はあなたのニーズをよりよく理解だと思います。私はあなたが仕事の独立したシーケンスを提出する方法を必要と仮定します。 this answerに投稿したコードをご覧ください。

+0

私は私の例でこれをうまく説明していませんでしたが、手順は前の手順が完了したことに依存しています。たとえば、stepOw()のリモート完了時にstepTwo()が実行されます。 stepTwo()は基本的にstepOne()で呼び出されたコンポーネントの補完コールバックです – irondwill

7

非同期操作(終了時にコールバックを実行する)を同期/ブロック化する場合は、ブロックキューを使用できます。あなたが望むなら、これをFutureオブジェクトで包み込むことができます。 、(バックグラウンドで実行されます)

BlockingQueue<Result> blockingQueue = new ArrayBlockingQueue<Result>(1);

  • があなたの非同期プロセスを起動し、それが行われますようにコールバックを書く:

    1. はただ一つの要素を保持することができブロッキングキューを定義します。その結果をブロッキングキューに追加します。あなたのフォアグラウンド/アプリケーションスレッドで

    2. 、それが(取る持っている)要素が利用可能になるまでブロックキューから:

      Result result = blockingQueue.take();

    私は(フォアグラウンドスレッドのニーズの前に似た何かを書きました将来のようなものを使ってリモートマシンからの非同期応答をブロックするには、例コードhereがあります。

  • +0

    'SynchronousQueue'はおそらくこの目的のためにはより良いでしょう – ZhongYu

    +2

    私は恐れている前にそこにいました。バックグラウンドスレッドがtake()と呼ばれるフォアグラウンドスレッドの前に完了するような競合状態があった場合、SynchronousQueueはバックグラウンドスレッドをブロックまたは例外を受け取る可能性があります。前述のOPのようにこれがFutureにラップされていた場合、Future.get()を呼び出す前にアプリケーションが他の作業をしていればよくあることです。 – npgall

    0

    あなたの手が汚れて取得したい場合は、この

    ResultObject result; 
    
    public void stepOne() 
    
        otherComponent.doStepOne(this); 
    
        synchronized(this) 
         while(result==null) this.wait(); 
        return result; 
    
    public void stepThree(ResultObject resultFromOtherComponent) 
    
        result = resultFromOtherComponent; 
    
        synchronized(this) 
         this.notify(); 
    

    それとも、より高いレベルの並行処理ツールを使用することができますを行うことができます、などなどBlockingQueueの、セマフォ、たCountDownLatch、フェイザーなど

    注意DoAJobはスレッドセーフではありません.2つのスレッドが同時にstepOneを呼び出すと、トラブルが発生します。

    +0

    ええ、それはかなり特殊なユースケース&アーキテクチャであるように思われるので、私はそのようなことをしなければならなくなるかもしれません。私は、wait()ループを実装する必要がないか、あまりにも多くのsynchronized()呼び出しでコードをジャンクすることを避けることを望んでいました。 – irondwill

    関連する問題