ランナブルの実装とスレッドの拡張

Runnableの実装とスレッドの拡張

1. 前書き

Runnableを実装するか、Threadクラスを拡張する必要がありますか?」 よくある質問です。

この記事では、実際にどのアプローチがより理にかなっているのか、そしてその理由を説明します。

2. Threadの使用

まず、Threadを拡張するSimpleThreadクラスを定義しましょう。

public class SimpleThread extends Thread {

    private String message;

    // standard logger, constructor

    @Override
    public void run() {
        log.info(message);
    }
}

このタイプのスレッドを実行する方法も見てみましょう。

@Test
public void givenAThread_whenRunIt_thenResult()
  throws Exception {

    Thread thread = new SimpleThread(
      "SimpleThread executed using Thread");
    thread.start();
    thread.join();
}

ExecutorServiceを使用してスレッドを実行することもできます。

@Test
public void givenAThread_whenSubmitToES_thenResult()
  throws Exception {

    executorService.submit(new SimpleThread(
      "SimpleThread executed using ExecutorService")).get();
}

これは、別のスレッドで単一のログ操作を実行するための非常に多くのコードです。

また、Javaは多重継承をサポートしていないため、SimpleThread cannot extend any other classに注意してください。

3. Runnableの実装

それでは、java.lang.Runnableインターフェースを実装する簡単なタスクを作成しましょう。

class SimpleRunnable implements Runnable {

    private String message;

    // standard logger, constructor

    @Override
    public void run() {
        log.info(message);
    }
}

上記のSimpleRunnableは、別のスレッドで実行したいタスクです。

それを実行するために使用できるさまざまなアプローチがあります。それらの1つは、Threadクラスを使用することです。

@Test
public void givenRunnable_whenRunIt_thenResult()
 throws Exception {
    Thread thread = new Thread(new SimpleRunnable(
      "SimpleRunnable executed using Thread"));
    thread.start();
    thread.join();
}

ExecutorServiceを使用することもできます。

@Test
public void givenARunnable_whenSubmitToES_thenResult()
 throws Exception {

    executorService.submit(new SimpleRunnable(
      "SimpleRunnable executed using ExecutorService")).get();
}

hereExecutorServiceについてもっと読むことができます。

現在インターフェースを実装しているので、必要に応じて別の基本クラスを自由に拡張できます。

Java 8以降、単一の抽象メソッドを公開するインターフェースはすべて、機能的なインターフェースとして扱われ、有効なラムダ式ターゲットになります。

We can rewrite the above Runnable code using a lambda expression

@Test
public void givenARunnableLambda_whenSubmitToES_thenResult()
  throws Exception {

    executorService.submit(
      () -> log.info("Lambda runnable executed!"));
}

4. RunnableまたはThread

簡単に言えば、通常、ThreadではなくRunnableを使用することをお勧めします。

  • Threadクラスを拡張する場合、そのメソッドをオーバーライドすることはありません。 代わりに、Threadがたまたま)を実装するRunnable (のメソッドをオーバーライドします。 これはIS-AThreadの原則の明らかな違反です

  • Runnableの実装を作成し、それをThreadクラスに渡すと、継承ではなく構成が利用されます。これはより柔軟です。

  • Threadクラスを拡張した後、他のクラスを拡張することはできません

  • Java 8以降、Runnablesはラムダ式として表すことができます

5. 結論

このクイックチュートリアルでは、Threadクラスを拡張するよりも、Runnableを実装する方が一般的に優れたアプローチであることがわかりました。

この投稿のコードはover on GitHubにあります。