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();
}
hereでExecutorServiceについてもっと読むことができます。
現在インターフェースを実装しているので、必要に応じて別の基本クラスを自由に拡張できます。
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にあります。