Javaにおける「implements Runnable」と「extends Thread」のコード例
Javaにおける「implements Runnable」と「extends Thread」の違い
Javaにおけるマルチスレッドプログラミングでは、複数のタスクを並行して実行することができます。この際、タスクの実行単位として、Thread
クラスまたはRunnable
インターフェースが使用されます。
implements Runnable
Runnable
インターフェースを実装することで、スレッドのタスクを定義します。Runnable
インターフェースには、run()
メソッドを定義する必要があります。このメソッドがスレッドの実際の処理を実行します。Runnable
インターフェースを実装したクラスは、直接スレッドではありません。スレッドを作成するには、Thread
クラスのコンストラクタにRunnable
オブジェクトを渡す必要があります。
extends Thread
Thread
クラスを継承することで、スレッド自体を定義します。Thread
クラスを継承したクラスは、直接スレッドです。スレッドを作成するために、クラスのインスタンスを生成するだけで済みます。
比較
特徴 | implements Runnable | extends Thread |
---|---|---|
スレッドの定義 | タスクの定義 | スレッド自体の定義 |
スレッドの作成 | Thread クラスのコンストラクタにRunnable オブジェクトを渡す | クラスのインスタンスを生成する |
継承 | 他のクラスを継承できる | Thread クラスを継承するため、他のクラスを継承できない |
例
// implements Runnable
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable thread is running.");
}
}
// extends Thread
class MyThread extends Thread {
public void run() {
System.out.println("Thread thread is running.");
}
}
public class Main {
public static void main(String[] args) {
Thread thread1 = new Thread(new MyRunnable());
thread1.start();
MyThread thread2 = new MyThread();
thread2.start ();
}
}
implements Runnable
は、タスクを定義するための柔軟な方法です。extends Thread
は、スレッド自体を定義するための直接的な方法ですが、他のクラスを継承できないという制限があります。- どちらの方法を使用するかは、設計上の要件や好みによって決まります。
Runnable
インターフェースは、他のスレッドから実行することもできます。Thread
クラスは、多くの便利なメソッドを提供しており、スレッドの管理や制御が容易です。
class MyRunnable implements Runnable {
public void run() {
System.out.println("Runnable thread is running.");
}
}
public class Main {
public static void main(String[] args) {
Thread thread = new Thread(new MyRunnable());
thread.s tart();
}
}
MyRunnable
クラスは、Runnable
インターフェースを実装しています。run()
メソッドは、スレッドの実際の処理を実行します。Main
クラスのmain()
メソッドで、MyRunnable
オブジェクトをThread
クラスのコンストラクタに渡し、新しいスレッドを作成します。thread.start()
メソッドで、スレッドを開始します。
class MyThread extends Thread {
public void run() {
System.out.println("Thread thread is running.");
}
}
public class Main {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start();
}
}
MyThread
クラスは、Thread
クラスを継承しています。Main
クラスのmain()
メソッドで、MyThread
クラスのインスタンスを生成し、新しいスレッドを作成します。
Javaスレッド実装の違い
- implements Runnableは、タスクを定義するための柔軟な方法です。他のクラスを継承できるため、複数のインターフェースを実装することができます。
- 両方の方法で、スレッドの処理は並行して実行されます。
Thread
クラスは、スレッドの優先度、名前、デーモンフラグなどの属性を設定することができます。
Callableインターフェース
Callable
インターフェースは、Runnable
インターフェースと似ていますが、戻り値を持つことができます。Callable
インターフェースを実装したクラスは、FutureTask
クラスを使用してスレッドを作成し、実行することができます。FutureTask
クラスは、スレッドの終了状態や結果を取得するためのメソッドを提供します。
ExecutorServiceインターフェース
ExecutorService
インターフェースは、スレッドプールを管理するためのインターフェースです。ExecutorService
インターフェースを使用して、複数のタスクをスレッドプールに提出することができます。- スレッドプールは、スレッドの再利用や管理を自動的に行います。
ForkJoinPoolクラス
ForkJoinPool
クラスは、ワークスチールアルゴリズムを使用して、タスクを分割し、並列に実行するフレームワークです。ForkJoinPool
クラスは、大規模なタスクを効率的に処理することができます。
コード例
// Callableインターフェース
import java.util.concurrent.*;
class MyCallable implements Callable<Integer> {
public Integer call() throws Exception {
return 42;
}
}
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService exe cutor = Executors.newSingleThreadExecutor();
Future<Integer> future = executor.submit(new MyCallable());
int result = future.get();
System.out.println(re sult);
executor.shutdown();
}
}
// ExecutorServiceインターフェース
import java.util.concurrent.*;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService exe cutor = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
executor.submit(() -> System.o ut.println("Task " + i));
}
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
}
}
// ForkJoinPoolクラス
import java.util.concurrent.*;
class MyRecursiveTask extends RecursiveTask<Integer> {
private final int threshold = 10;
private final int[] array;
private final int start;
private final int end;
public MyRecursiveTask(int[] array, int start, int end) {
this.array = array;
this.start = start;
this.end = end;
}
protected Integer comp ute() {
if (end - start <= threshold) {
// 小さい範囲は直接計算
int sum = 0;
for (int i = start; i < end; i++) {
sum += array[i];
}
return sum;
} else {
// 大きい範囲は分割して再帰的に計算
int mid = (start + end) / 2;
MyRecursiveTask left = new MyRecursiveTask(array, start, mid);
MyRecursiveTask right = new MyRecursiveTask(array, mid, end);
left.fork();
int rightResult = right.compute();
int leftResult = left.join();
return leftResult + rightResult;
}
}
}
public class Main {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5};
ForkJoinPool pool = new ForkJoinPool();
MyRecursiveTask task = new MyRecursiveTask(array, 0, array.length);
int result = pool.invoke(task);
System.out.println(result);
}
}
implements Runnable
とextends Thread
は、基本的なスレッド実装方法です。Callable
インターフェースは、戻り値を持つタスクを定義することができます。
java multithreading runnable