50-Futureを使用する際の注意点は何ですか?Futureは新しいスレッドを生成しますか?

今後の注意点
  1. forループがFutureの結果をバッチで取得する場合、ブロックするのは簡単です。getメソッドを呼び出すときは、タイムアウト制限を使用する必要があります。

Futuresの場合、最初の注意点は、forループがFuturesの結果をバッチで取得するときにブロックしやすいことです。getメソッドを呼び出すときは、タイムアウトを使用して制限する必要があります。

この状況が何であるかを見てみましょう。

まず、実行するタスクが全部で4つあるとすると、それらをスレッドプールに入れ、get()メソッドを実行して取得する1から4の順序で取得します。コードは次のとおりです。次のように:

public class FutureDemo {
    
    
    public static void main(String[] args) {
    
    
        //创建线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        //提交任务,并用 Future 接收返回结果
        ArrayList<Future> allFutures = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
    
    
            Future<String> future;
            if (i == 0 || i == 1) {
    
    
                future = service.submit(new SlowTask());
            } else {
    
    
                future = service.submit(new FastTask());
            }
            allFutures.add(future);
        }
        for (int i = 0; i < 4; i++) {
    
    
            Future<String> future = allFutures.get(i);
            try {
    
    
                String result = future.get();
                System.out.println(result);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            } catch (ExecutionException e) {
    
    
                e.printStackTrace();
            }
        }
        service.shutdown();
    }
    static class SlowTask implements Callable<String> {
    
    
        @Override
        public String call() throws Exception {
    
    
            Thread.sleep(5000);
            return "速度慢的任务";
        }
    }
    static class FastTask implements Callable<String> {
    
    
        @Override
        public String call() throws Exception {
    
    
            return "速度快的任务";
        }
    }
}

コードでは、新しいスレッドプールを作成し、リストを使用して4つのFutureを格納していることがわかります。その中で、最初の2つのFutureに対応するタスクは遅いタスク、つまりコードの下のSlowTaskであり、最後の2つのFutureに対応するタスクは速いタスクです。遅いタスクは実行時に5秒で完了しますが、速いタスクは非常に高速に実行でき、ほとんど時間がかかりません。

これらの4つのタスクを送信した後、forループを使用してgetメソッドを実行し、実行結果を取得して、結果を出力します。

実行結果は以下のとおりです。

速度慢的任务
速度慢的任务
速度快的任务
速度快的任务

ご覧のとおり、この実行の結果は4行のステートメントを出力し、最初の2つは低速タスクであり、後の2つは高速タスクです。結果は正しいですが、実際には実行中に5秒間待機してから、これらの4行のステートメントを非常に高速に出力します。
ここに画像の説明を挿入します
ここで問題があります。つまり、3番目のタスクの量が比較的少なく、結果をすばやく返すことができ、4番目のタスクもすぐに結果を返します。ただし、最初の2つのタスクは非常に遅いため、getメソッドを使用して実行すると、最初のタスクでスタックします。つまり、この時点では3番目と4番目のタスクの結果は非常に早い段階で取得されますが、これをforループメソッドを使用して結果を取得すると、3番目と4番目のタスクを時間内に取得できません。タスクの結果。最初のタスクの結果は5秒後まで取得できません。その後、2番目のタスクの結果を取得できます。次に、3番目と4番目のタスクの順番になります。

ネットワーク上の理由により、最初のタスクが最大1分間結果を返すことができない場合があると仮定すると、この時点では、メインスレッドがスタックしたままになり、プログラムの効率に影響します。

この時点で、Futureのget(long timeout、TimeUnit unit)メソッドをタイムアウトパラメーターとともに使用して、この問題を解決できます。このメソッドの機能は、限られた時間内に結果が返されない場合、TimeoutExceptionがスローされ、例外をキャッチまたは再度スローできるため、常にスタックするとは限りません。

2.未来のライフサイクルを後退させることはできません

Futureのライフサイクルを元に戻すことはできません。タスクが完了すると、「完了」状態で永続的に停止し、最初から再開することも、計算を完了したFutureがタスクを再実行することもできません。

これはスレッドとスレッドプールの状態と同じであり、スレッドとスレッドプールの状態を回帰することはできません。スレッドの状態と流路については、図に示すように、前の3で説明しました。
ここに画像の説明を挿入します
忘れてしまった方は、振り返ってもう一度見てください!

Futureは新しいスレッドを生成しますか?

最後に、この質問にもう一度答えましょう。Futureは新しいスレッドを生成しますか?

Threadクラスの継承とRunnableインターフェースの実装に加えて、新しいスレッドを生成する3番目の方法、つまりCallableとFutureを使用する方法があるということわざがあります。これは、戻り値を持つスレッドを作成する方法と呼ばれます。 。このステートメントは正しくありません。

実際、CallableとFutureは、それ自体で新しいスレッドを生成することはできません。タスクを実行するには、Threadクラスやスレッドプールなどの他のスレッドを使用する必要があります。たとえば、Callableがスレッドプールに送信された後、実際にCallableを実行するのはスレッドプール内のスレッドであり、スレッドプール内のスレッドはThreadFactoryによって生成されます。ここで生成された新しいスレッドは何の関係もありません。 CallableとFutureを使用するため、Future新しいスレッドは生成されません。

Futureに関する2つの注意点:まず、取得時にタイムアウト制限を使用する必要があります。次に、Futureのライフサイクルを回帰できません。次に、CallableとFutureは、実際には新しいスレッドを作成する3番目の方法ではないと言われています。

おすすめ

転載: blog.csdn.net/Rinvay_Cui/article/details/111056577