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

は他のクラスを拡張できません


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();
}


ExecutorService

の詳細については、リンク:/java-executor-service-tutorial[こちら]を参照してください。

私たちは今インターフェースを実装しているので、必要ならば別の基本クラスを自由に拡張することができます。

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

  • 上記のRunableコードはラムダ式を使って書き換えることができます。

@Test
public void givenARunnableLambda__whenSubmitToES__thenResult()
  throws Exception {

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


4

Runnable

または

Thread



簡単に言うと、一般的には

Thread

の上に

Runnable

を使用することをお勧めします。


  • Thread

    クラスを拡張するときは、そのクラスをオーバーライドしません。

メソッド代わりに、

__Runnable(


which

Thread

)のメソッドをオーバーライドします。





を実装しています。これはIS-Aの明らかな違反です。
原理
**

Runnable__の実装を作成してそれを


Thread

クラスは継承ではなく合成を利用します – これはもっと
フレキシブル
**

Thread

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

  • Java 8以降、

    Runnables

    はラムダとして表すことができます。


5結論

このクイックチュートリアルでは、

Runnable

を実装することが

Thread

クラスを拡張するよりも一般的に優れた方法であることを確認しました。

この記事のコードはhttps://github.com/eugenp/tutorials/tree/master/core-java-concurrency[over on GitHub]にあります。