Javaスレッドへのパラメーターの受け渡し

 1. 概要

このチュートリアルでは、Java link:/java-thread-lifecycle[thread]にパラメーターを渡すために使用できるさまざまなオプションを実行します。

2. スレッドの基礎

念のため、https://www.baeldung.com/java-runnable-vs-extending-thread [implementing _Runnable _] __ __or link:/java-でthread__ ___をJavaで作成できます。 runnable-callable [_Callable_]。
スレッドを実行するには、_Thread#start_(_Runnable_のインスタンスを渡すことで)またはlink:/thread-pool-java-and-guava [スレッドプールを使用]にサブミットして呼び出すことができます。 _https://www.baeldung.com/java-executor-service-tutorial [ExecutorService] ._
*ただし、これらのアプローチはいずれも追加のパラメーターを受け入れません。*
スレッドにパラメーターを渡すために何ができるか見てみましょう。

3. コンストラクターでパラメーターを送信

パラメーターをスレッドに送信する最初の方法は、コンストラクターで__Runnable __or _Callable_にパラメーターを提供することです。
数値の配列を受け入れ、その平均を返す_AverageCalculator_を作成しましょう。
public class AverageCalculator implements Callable<Double> {

    int[] numbers;

    public AverageCalculator(int... numbers) {
        this.numbers = numbers == null ? new int[0] : numbers;
    }

    @Override
    public Double call() throws Exception {
        return IntStream.of(numbers).average().orElse(0d);
    }
}
次に、平均的な計算スレッドにいくつかの数値を提供し、出力を検証します。
@Test
public void whenSendingParameterToCallable_thenSuccessful() throws Exception {
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    Future<Double> result = executorService.submit(new AverageCalculator(1, 2, 3));
    try {
        assertEquals(2.0, result.get().doubleValue());
    } finally {
        executorService.shutdown();
    }
}
これが機能する理由は、スレッドを起動する前にクラスの状態を渡したためです。*

4. クロージャーを介してパラメーターを送信

パラメーターをスレッドに渡す別の方法は、closure __.__を作成することです
_closure_は、親のスコープの一部を継承できるスコープです。*ラムダと匿名の内部クラスで見られます。*
前の例を拡張して、2つのスレッドを作成しましょう。
最初のものは平均を計算します:
executorService.submit(() -> IntStream.of(numbers).average().orElse(0d));
そして、2番目は合計を行います:
executorService.submit(() -> IntStream.of(numbers).sum());
同じパラメータを両方のスレッドに渡し、結果を取得する方法を見てみましょう。
@Test
public void whenParametersToThreadWithLamda_thenParametersPassedCorrectly()
  throws Exception {
    ExecutorService executorService = Executors.newFixedThreadPool(2);
    int[] numbers = new int[] { 4, 5, 6 };

    try {
        Future<Integer> sumResult =
          executorService.submit(() -> IntStream.of(numbers).sum());
        Future<Double> averageResult =
          executorService.submit(() -> IntStream.of(numbers).average().orElse(0d));
        assertEquals(Integer.valueOf(15), sumResult.get());
        assertEquals(Double.valueOf(5.0), averageResult.get());
    } finally {
        executorService.shutdown();
    }
}
覚えておくべき重要なことの1つは、https://www.baeldung.com/java-8-lambda-expressions-tips [*パラメーターを効果的に最終的に保持*]することです。そうしないと、クロージャーに渡すことができません。
*また、どこでも同じ並行性ルールがここに適用されます。*スレッドの実行中に_numbers_配列の値を変更した場合、https://www.baeldung.com/java-なしで表示されるという保証はありません。 synchronized-collections [紹介] link:/java-synchronized [同期]。
ここでまとめると、古いバージョンのJavaを使用している場合、匿名の内部クラスも機能していました。
final int[] numbers = { 1, 2, 3 };
Thread parameterizedThread = new Thread(new Callable<Double>() {
    @Override
    public Double call() {
        return calculateTheAverage(numbers);
    }
});
parameterizedThread.start();

5. 結論

この記事では、パラメーターをJavaスレッドに渡すために使用できるさまざまなオプションを発見しました。
いつものように、コードサンプルはhttps://github.com/eugenp/tutorials/tree/master/core-java-modules/core-java-concurrency-advanced[Githubで]から入手できます。