幸福なプログラマ

プログラマは幸福になれる。

非同期処理にはThreadを直接使わずにExecutorServiceを使用する

一個前の記事

MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start();

みたいな感じでThreadクラスのコンストラクタRunnable実装したサブクラスを渡して非同期処理をしようと書いたけれど、以下の観点からおすすめできません。

  • 複数Threadを作成する際、スレッド作成時間がパフォーマンスに影響を与える可能性がある。
  • 作成したThreadがそのまま放置される。

そこで一度作成したスレッドを待機(プール)させ、必要に応じてスレッドを取り出してタスクを割り当て、タスクが完了したらスレッドを再度プールさせる(スレッドを再利用する)スレッドプールという仕組みを活用してパフォーマンスの向上を図ります。

スレッドプールはExecutorクラスのメソッドで作成できます。
これによりExecutorServiceオブジェクトが生成され、スレッドの実行を行います。

ExecutorService executorService = null;
try {
    executorService = Executors.newFixedThreadPool(2);
    executorService.execute(new OneRunnable());
    executorService.execute(new TwoRunnable());
} finally {
    executorService.shutdown();
}

Executors#newFixedThreadPool(int) でスレッドプールを作成します。
executeにRunnableオブジェクトを渡すと自動的にタスクをスレッド意に割り当てて実行されます。
Executorsは主に以下のようなメソッドを持ちます。

メソッド 機能
newFixedThreadPool 引数で指定した数のスレッドを常時保持するスレッドプールを作成。
タスクは空いているスレッドに割り当てられます。
newCachedThreadPool タスクを割り当てる度に新しいスレッドを生成し、そのスレッドを使いまわします。
一定時間使用されなかったスレッドは消滅します。
newScheduledThreadPool タスクを一定時間ごとに実行するスレッドを持つスレッドプールを作成。
newSingleThreadExecutor 1つのスレッドを使いまわすスレッドプールを作成。
割り当てられたタスクは順番に実行されます。