2015-12-14 15 views
7

完了までに時間がかかるメソッドから結果を得るために、実際にオブジェクトを返さないようにするため、可能な限り効果的に処理したいと考えています。ここで私が達成しようとしているものの例です:。将来の成果を得るには?

public static void main (String[] args) { 
     Object obj = someMethod(); 

     System.out.println("The object is" + obj + ", wooh!"); 
    } 

    public void callObject() { 
     // Sends request for the object 
    } 

    public void receiveObject(Object object) { 
     // Received the object 
    } 

    public Object someMethod() { 
     callObject(); 
     // delay whilst the object is being received 
     // return received object once received, but how? 
    } 

callObjectは、オブジェクトを取得するために呼び出すメソッドは、しかし、別の方法は、私はのsomeMethod()を呼び出すことができるようにしたい内のオブジェクトと呼ばれています実際の呼び出しと受信が別々のメソッドであっても、最終的に受け取る内容を返すことができます。

私はFutureTasksとCallablesを使用してみました。だと思いますが、実装方法はあまり分かりません。

申し訳ありませんが自分自身について説明していない場合は、必要に応じてさらに情報を提供します。

ありがとうございます!

答えて

5

長時間実行されているタスクを非同期的に起動するメソッドを記述できます。その後、空の状態ですが、長時間実行されているタスクが完了すると、オブジェクトが返されます。他のプログラミング言語では、これは約束と呼ばれます。

ここは簡単な例です。私はsomeLongAsyncOperationというメソッドを作成し、それはしばらく時間がかかるものを実行します。これをシミュレートするには、私は答えを生成する前に3秒間寝るだけです。

import java.util.UUID; 
import java.util.concurrent.*; 

public class Test { 

    private static final ExecutorService executorService = Executors.newSingleThreadExecutor(); 

    public Future<MyAnswer> someLongAsyncOperation(){ 

     Future<MyAnswer> future = executorService.submit(() -> { 
      Thread.sleep(3000); 
      return new MyAnswer(UUID.randomUUID().toString()); 
     }); 

     return future; 
    } 


    public static void main(String[] args) throws Exception { 

     System.out.println("calling someLongAsyncOperation ..."); 
     Future<MyAnswer> future = new Test().someLongAsyncOperation(); 
     System.out.println("calling someLongAsyncOperation done."); 

     // do something else 

     System.out.println("wait for answer ..."); 
     MyAnswer myAnswer = future.get(); 
     System.out.printf("wait for answer done. Answer is: %s", myAnswer.value); 

     executorService.shutdown(); 
    } 

    static class MyAnswer { 
     final String value; 

     MyAnswer(String value) { 
      this.value = value; 
     } 
    } 
    } 

あなたは、この小さなテストクラスを実行する場合は、someLongAsyncOperation戻って速いこと、わかりますが、future.get();を呼び出すときに、私たちは操作が完了するのを待ちます。

これで、複数のlongAsyncOperationの開始のようなことができるようになり、並列実行が可能になりました。そしてすべてが完了するまで待ってください。

これは出発点として機能しますか?

あなたはこのようなsomeMethodを実装することができ

EDIT:それを呼び出し、結果を待つことによって、再び非同期操作シンクロンを行います

public MyAnswer someMethod() throws ExecutionException, InterruptedException { 
     Future<MyAnswer> future = someLongAsyncOperation(); // kick of async operation 
     return future.get(); // wait for result 
    } 

import java.util.UUID; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import java.util.concurrent.locks.Condition; 
import java.util.concurrent.locks.Lock; 
import java.util.concurrent.locks.ReentrantLock; 

public class Test2 { 

    private static final ExecutorService executorService = Executors.newSingleThreadExecutor(); 
    private Object receivedObject; 
    private final Object mutex = new Object(); 

    public static void main (String[] args) throws InterruptedException { 
     Object obj = new Test2().someMethod(); 

     System.out.println("The object is" + obj + ", wooh!"); 

     executorService.shutdown(); 
    } 

    public void callObject() { 

     System.out.println("callObject ..."); 

     // Sends request for the object asynchronously! 
     executorService.submit(() -> { 

      // some wait time to simulate slow request 
      try { 
       Thread.sleep(3000); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 

      // provide object to callback 
      receiveObject(UUID.randomUUID().toString()); 
     }); 

     System.out.println("callObject done."); 
    } 

    public void receiveObject(Object object) { 

     System.out.println("receiveObject ..."); 

     synchronized (mutex) { 
      this.receivedObject = object; 
      mutex.notify(); 
     } 

     System.out.println("receiveObject done."); 
    } 

    public Object someMethod() throws InterruptedException { 

     System.out.println("someMethod ..."); 

     synchronized (mutex) { 
      callObject(); 
      while(this.receivedObject == null){ 
       mutex.wait(); 
      } 
     } 

     System.out.println("someMethod done."); 
     return this.receivedObject; 
    } 

} 

someMethod待つreceivedObjectが存在するまで:ここ

EDIT2

は、通知/待機使用する別の例です。 receiveObject到着時に通知します。

+0

それは良い出発点ですが、私は受信方法は、その結果とsomeLongAsyncOperationを提供する方法についてはわからないんですか? – Anonomoose

+0

操作が完了したときに 'receiveObject'を呼び出すように思えます。これは将来の代わりにコールバックに似ています。私は例を提供しようとしましょう... –

+0

ええ、それは私が行っているものです - ごめんなさい! – Anonomoose

0

あなたがコールバックを必要とする:

private abstract class Callback<T>{ 
    run(T object); 
} 


public Object someMethod() { 
    callObject(new Callback<Object>() 
    { 
     @Override 
     public void run(Object object) 
     { 
      System.out.println("The object is" + object + ", wooh!"); 
     } 
    }) 

} 

public void callObject(Callback<Object> callback) { 
    // Sends request for the object 
    callback.run(object); 
} 
+0

有望に見えますが、オブジェクトの受信はどこに届くのでしょうか? – Anonomoose

+0

コールバックで取得すると、そこからSystem.outの代わりに呼び出すことができます。もちろん、コールバックがバックスレッドで実行され、コールバックがメインスレッドで実行されることを確認する必要があります。しかし、これはどのスレッドシステムを使用するかによって異なります。 – yedidyak

+0

さて、結果を参照することによって、結果が受信されたことをどのように知ることができますか? – Anonomoose

関連する問題