1. ホーム
  2. java

Future.get()ブロックへのメソッド呼び出し。それは本当に望ましいことなのか?

2023-07-20 01:48:47

質問

重複としてマークする前に、質問をよく読んでください。

以下は擬似コードのスニペットです。 私の質問は、以下のコードは並列非同期処理の概念そのものを打ち壊すものではないのでしょうか?

私がこれを尋ねる理由は、以下のコードでメインスレッドが別のスレッドで実行されるタスクを送信するためです。キューでタスクを送信した後、タスクが値を返すために Future.get() メソッドでブロックします。私は、タスクを別のスレッドにサブミットして結果を待つよりも、むしろメインスレッドで実行させたいと考えています。新しいスレッドでタスクを実行することによって、私は何を得ることができますか?

限られた時間だけ待つなどの方法があることは承知していますが、それでは本当に結果を気にする場合はどうすればよいのでしょうか?実行するタスクが複数ある場合、問題はさらに悪化します。同期的に作業を行うだけのような気がします。私は、非ブロッキングリスナーインターフェースを提供するGuavaライブラリの存在を知っています。しかし、私はFuture.get()APIについて私の理解が正しいかどうかを知りたいと考えています。もし正しいのであれば、なぜFuture.get()はブロックするように設計されており、それによって並列処理の全プロセスが台無しになるのでしょうか?

注 - 記録のために、私は JAVA 6 を使用しています。

public static void main(String[] args){

private ExectorService executorService = ...

Future future = executorService.submit(new Callable(){
    public Object call() throws Exception {
        System.out.println("Asynchronous Callable");
        return "Callable Result";
    }
});

System.out.println("future.get() = " + future.get());
}

どのように解決するのですか?

Future は、以下の方法を提供します。 isDone() これはブロックされず、計算が完了すれば真を、そうでなければ偽を返します。

Future.get() は計算の結果を取得するために使用されます。

いくつかのオプションがあります。

  • コール isDone() を呼び、結果が準備できたら get() ブロックがないことに注意してください。
  • で無期限にブロックします。 get()
  • 指定されたタイムアウトの間、ブロックする。 get(long timeout, TimeUnit unit)

全体 Future API は、並列タスクを実行するスレッドから値を取得する簡単な方法を提供するためにあります。これは、上記の箇条書きで説明されているように、同期でも非同期でも可能です。

キャッシュを用いた更新の例

以下は、キャッシュの実装を Java並行処理の実践 の優れた使用例です。 Future .

  • 計算がすでに実行されている場合、計算結果に関心のある呼び出し側は計算の終了を待ちます。
  • 結果がキャッシュに準備されている場合、呼び出し元はそれを収集します。
  • 結果が準備できておらず、まだ計算が始まっていない場合、呼び出し元は計算を開始し、結果を Future でラップします。

これはすべて、簡単に Future APIで簡単に実現できます。

package net.jcip.examples;

import java.util.concurrent.*;
/**
 * Memoizer
 * <p/>
 * Final implementation of Memoizer
 *
 * @author Brian Goetz and Tim Peierls
 */
public class Memoizer <A, V> implements Computable<A, V> {
    private final ConcurrentMap<A, Future<V>> cache
            = new ConcurrentHashMap<A, Future<V>>();
    private final Computable<A, V> c;

public Memoizer(Computable<A, V> c) {
    this.c = c;
}

public V compute(final A arg) throws InterruptedException {
    while (true) {

        Future<V> f = cache.get(arg);
        // computation not started
        if (f == null) {
            Callable<V> eval = new Callable<V>() {
                public V call() throws InterruptedException {
                    return c.compute(arg);
                }
            };

            FutureTask<V> ft = new FutureTask<V>(eval);
            f = cache.putIfAbsent(arg, ft);
            // start computation if it's not started in the meantime
            if (f == null) {
                f = ft;
                ft.run();
            }
        }

        // get result if ready, otherwise block and wait
        try {
            return f.get();
        } catch (CancellationException e) {
            cache.remove(arg, f);
        } catch (ExecutionException e) {
            throw LaunderThrowable.launderThrowable(e.getCause());
        }
    }
  }
}