1. 概要

このチュートリアルでは、Javaスレッドにパラメーターを渡すために使用できるさまざまなオプションを実行します。

2. スレッドの基礎

簡単に言うと、Javaでスレッド を作成するには、 Runnable またはCallableを実装します。

スレッドを実行するには、を呼び出すことができます Thread#start (のインスタンスを渡すことによって実行可能 ) またスレッドプールを使用するに提出することによって ExecutorService。

ただし、これらのアプローチはどちらも追加のパラメーターを受け入れません。

パラメータをスレッドに渡すために何ができるか見てみましょう。

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

スレッドにパラメーターを送信する最初の方法は、コンストラクターのRunnableまたは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. クロージャーを介したパラメーターの送信

パラメータをスレッドに渡す別の方法は、クロージャを作成するです。

クロージャは、その親のスコープの一部を継承できるスコープです–ラムダと匿名の内部クラスで表示されます。

前の例を拡張して、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つは、パラメーターを効果的にファイナルに保つことです。そうしないと、パラメーターをクロージャーに渡すことができなくなります。

また、ここではどこでも同じ同時実行ルールが適用されます。スレッドの実行中に numbers 配列の値を変更した場合、なしで値が表示される保証はありません。 ]紹介いくつかの同期

最後に、匿名の内部クラスも機能します。たとえば、古いバージョンの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スレッドにパラメーターを渡すために使用できるさまざまなオプションを発見しました。

いつものように、コードサンプルはGithubから入手できます。