web-dev-qa-db-ja.com

CallableよりもFutureTaskを使用する利点は何ですか?

タスクの送信と結果のポーリングには2つの方法があります

_FutureTask futureTask = new FutureTask<String>(callable);
_
  1. CallableFutureを組み合わせて使用​​し、ExecutorServiceで送信します。 future.get()を使用して結果を取得します。

    _Future future = service.submit(callable);
    _
  2. FutureTaskを使用します。これはCallableをラップし、FutureTaskを使用して結果を取得します。

    _service.execute(task);
    _

FutureTask + Callable +将来の組み合わせを使用する利点は何ですか?

19
Amrish Pandey

ほとんど間違いなく、まったくありません。 AbstractExecutorServiceの-​​ GrepCode を簡単に参照すると、これらの各メソッドはCallable/RunnableFutureをご利用ください。

protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

public Future<?> submit(Runnable task) {
    // ...
    RunnableFuture<Object> ftask = newTaskFor(task, null);
    execute(ftask);
    return ftask;
}

public <T> Future<T> submit(Runnable task, T result) {
    // ...
    RunnableFuture<T> ftask = newTaskFor(task, result);
    execute(ftask);
    return ftask;
}

public <T> Future<T> submit(Callable<T> task) {
    // ...
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}
8
OldCurmudgeon

Futureを使用して、呼び出し可能なタスクのステータスを確認し、返されたオブジェクトを取得できます。 Callableが完了するのを待ってから結果を返すことができるget()メソッドを提供します。

Futureには、関連するCallableタスクをキャンセルするためのcancel()メソッドが用意されています。結果を待機する時間を指定できるget()メソッドのオーバーロードバージョンがあり、現在のスレッドが長時間ブロックされないようにすると便利です。関連する呼び出し可能タスクの現在のステータスを確認するためのisDone()およびisCancelled()メソッドがあります。

1秒後にタスクを実行するスレッドの名前を返すCallableタスクの簡単な例を次に示します。 Executorフレームワークを使用して100個のタスクを並列実行し、Futureを使用して送信されたタスクの結果を取得しています。

    import Java.util.ArrayList;
    import Java.util.Date;
    import Java.util.List;
    import Java.util.concurrent.Callable;
    import Java.util.concurrent.ExecutionException;
    import Java.util.concurrent.ExecutorService;
    import Java.util.concurrent.Executors;
    import Java.util.concurrent.Future;

    public class MyCallable implements Callable<String> {

        @Override
        public String call() throws Exception {
            Thread.sleep(1000);
            //return the thread name executing this callable task
            return Thread.currentThread().getName();
        }

        public static void main(String args[]){
            //Get ExecutorService from Executors utility class, thread pool size is 10
            ExecutorService executor = Executors.newFixedThreadPool(10);
            //create a list to hold the Future object associated with Callable
            List<Future<String>> list = new ArrayList<Future<String>>();
            //Create MyCallable instance
            Callable<String> callable = new MyCallable();
            for(int i=0; i< 100; i++){
                //submit Callable tasks to be executed by thread pool
                Future<String> future = executor.submit(callable);
                //add Future to the list, we can get return value using Future
                list.add(future);
            }
            for(Future<String> fut : list){
                try {
                    //print the return value of Future, notice the output delay in console
                    // because Future.get() waits for task to get completed
                    System.out.println(new Date()+ "::"+fut.get());
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }
            //shut down the executor service now
            executor.shutdown();
        }
    }

ここで、FutureTaskはFutureインターフェースの基本的な具体的な実装であり、非同期処理を提供します。これには、タスクを開始およびキャンセルするメソッドと、FutureTaskの状態が完了したかキャンセルされたかを返すことができるメソッドが含まれています。将来のタスクを作成するために呼び出し可能なオブジェクトが必要であり、次にJava Thread Pool Executorを使用してこれらを非同期に処理できます。

簡単なプログラムでFutureTaskの例を見てみましょう。

FutureTaskは呼び出し可能なオブジェクトを必要とするため、単純なCallable実装を作成します。

    public class MyCallable implements Callable<String> {

    private long waitTime;

    public MyCallable(int timeInMillis){
        this.waitTime=timeInMillis;
    }
    @Override
    public String call() throws Exception {
        Thread.sleep(waitTime);
        //return the thread name executing this callable task
        return Thread.currentThread().getName();
    }

}

    import Java.util.concurrent.ExecutionException;
import Java.util.concurrent.ExecutorService;
import Java.util.concurrent.Executors;
import Java.util.concurrent.FutureTask;
import Java.util.concurrent.TimeUnit;
import Java.util.concurrent.TimeoutException;

public class FutureTaskExample {

    public static void main(String[] args) {
        MyCallable callable1 = new MyCallable(1000);
        MyCallable callable2 = new MyCallable(2000);

        FutureTask<String> futureTask1 = new FutureTask<String>(callable1);
        FutureTask<String> futureTask2 = new FutureTask<String>(callable2);

        ExecutorService executor = Executors.newFixedThreadPool(2);
        executor.execute(futureTask1);
        executor.execute(futureTask2);

        while (true) {
            try {
                if(futureTask1.isDone() && futureTask2.isDone()){
                    System.out.println("Done");
                    //shut down executor service
                    executor.shutdown();
                    return;
                }

                if(!futureTask1.isDone()){
                //wait indefinitely for future task to complete
                System.out.println("FutureTask1 output="+futureTask1.get());
                }

                System.out.println("Waiting for FutureTask2 to complete");
                String s = futureTask2.get(200L, TimeUnit.MILLISECONDS);
                if(s !=null){
                    System.out.println("FutureTask2 output="+s);
                }
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }catch(TimeoutException e){
                //do nothing
            }
        }

    }

}
7
Mudassar