Javaにおけるスレッド生成パターンの実践ガイド

Thread クラスを継承する方法

class PrimeCounter extends Thread {
    @Override
    public void run() {
        System.out.println("スレッド名: " + Thread.currentThread().getName());
    }
}

public static void main(String[] args) {
    PrimeCounter counter = new PrimeCounter();
    counter.start();
}

Runnable インターフェースを実装する方法

class ImageProcessor implements Runnable {
    @Override
    public void run() {
        System.out.println("実行スレッド: " + Thread.currentThread().getName());
    }
}

public static void main(String[] args) {
    ImageProcessor task = new ImageProcessor();
    Thread worker = new Thread(task);
    worker.start();
}

継承方式と実装方式の違い:Thread クラスが Java におけるスレッドの唯一の抽象表現である一方、Runnable は業務ロジックを切り離した独立したタスクとして扱える。Thread は任意の Runnable を受け取り実行できるため、より柔軟な設計が可能。

非同期結果を取得する Future パターン

Thread や Runnable では戻り値を返せないが、Future を使うことでスレッドの実行結果を取得できる。

  • FutureTaskCallable を渡してインスタンス化
  • その FutureTaskThread に渡して起動
  • Future#get() で結果を取得(ブロッキング)
public static void main(String[] args) throws Exception {
    FutureTask<String> task = new FutureTask<>(() -> {
        Thread.sleep(2000);
        return "処理完了";
    });

    Thread runner = new Thread(task);
    runner.start();

    System.out.println(task.get()); // "処理完了"
}

「スレッド生成は何通りあるか?」という設問への答え

結論:公式には 2 通り(Thread 継承、Runnable 実装)。

  • Thread コンストラクタを new して start() を呼ぶ以外に、実質的な手段はない。
  • Callable + FutureTask は内部で Runnable にラップされるため Runnable 実装と同類。
  • ExecutorService などのスレッドプールは「既存スレッドの再利用」であり、新規スレッド生成とは区別される。

start() と run() の挙動差

メソッド意味実行回数内部動作
start() 新規 OS スレッドを起動し、スケジューラに登録 1 回まで(2 回目は IllegalThreadStateException) JNI の start0() を呼び出す
run() 単なるインスタンスメソッドとして実行 何度でも呼べる 通常の Java メソッド呼び出し

要するに new Thread(...) はあくまで Java オブジェクトであって、start() を叩くことで初めて OS レベルのスレッドが生成される。

タグ: Java Thread Runnable Callable FutureTask

6月5日 17:28 投稿