はじめに
仕事でスレッドプールを利用する機会があるので, Java でスレッドプールをつかう方法を調べてみた.
Java には, JDK1.5 から ExecutorService という便利なライブラリがあるようだ.
スレッドプールとは
はじめに, スレッドプールについての一般的な説明.
スレッドプールとは, 複数のスレッドをあらかじめ作成して待機させておき, タスクが来たら待っているスレッドにタスクを割り当てて 処理を開始させる仕組み.
スレッドの作成と破棄は, それなりにオーバーヘッドがある. そこで, スレッドは暇な時に作成しておいて, 必要になったときにスレッドに処理を割り当てることで, コンテキストスイッチ程度の軽いオーバヘッドで済ますことができる.
また, システム内のメモリは有限なので, 無限にスレッドを作成することはできない. 一度に利用できるスレッド数を制限することで, システムのリソースを制限することができるようになる.
Java でのスレッドプール実装
Executors
Executors クラスは, ExecutorService 生成のための static ファクトリーメソッドをもつ ユーティリティクラス.
主に, 以下のメソッドを用いる.
newFixedThreadPool 指定数スレッドを確保 newSingleThreadExecutor 単一スレッドを確保 newSingleThreadScheduledExecutor 指定期間おきに実行するスレッド (単一スレッド) newScheduledThreadPool 指定時間おきに実行するスレッド
ExecutorService
ExecutorService キューをもつ,スレッドプール.
主に, 以下のメソッドを用いる.
execute タスクを送信する. submit タスクの計算結果や状態を取得するための, Future オブジェクトを返す. shutdown シャットダウンを実行. 以前に送信したタスクは実行, 新規タスクは拒否
ちなみに, Executor というものもある.
ExecutorService は Executor を継承している. Executor は execute メソッドしかもたない.
Execotor にコマンドパターンを実装したものが ExecutorService.
- java - what’s the difference between Executor and ExecutorService? - Stack Overflow
- Java で Command Pattern を実装してみた | Futurismo
ちなみに
ちなみに, coursera の POSA でスレッドプールの Assignment がある.
Code
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.lang.Thread;
class SampleThreadPool {
private static class Action implements Runnable {
@Override
public void run () {
System.out.println ("Hello!!");
try { Thread.sleep (1000); } catch (InterruptedException e){}
}
}
public static void main (String[] args) {
// Create Single Thread Pool
ExecutorService executor = Executors.newSingleThreadExecutor ();
// Execute Tasks
executor.execute (new Action ());
executor.execute (new Action ());
// End
executor.shutdown ();
}
}
追記: 割り込み例外をあげる (2015/03/05)
割り込み例外をあげるには, 以下のような手順を踏む.
- execute () メソッドの代わりに submit () をコール
- future オブジェクトを取得
- future.cancel (true)
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.HashMap;
import java.lang.Thread;
class ThreadInteraptSample {
private static class Action implements Runnable {
public int id;
public Action (int id) {
this.id = id;
}
@Override
public void run () {
System.out.println ("id=" + id + " start!!");
try {
Thread.sleep (2000);
System.out.println ("Time out!!");
} catch (InterruptedException e){
System.out.println ("Interrupted id=" + id);
}
}
}
// https://java.keicode.com/lang/multithreading-cancel.php
public static void main (String[] args) {
Future future1, future2, future3;
// Create Single Thread Pool
ExecutorService executor = Executors.newSingleThreadExecutor ();
// Execute Tasks
Action act1 = new Action (1);
Action act2 = new Action (2);
Action act3 = new Action (3);
HashMap<Action, Future> map = new HashMap<Action, Future>();
map.put (act1, future1 = executor.submit (act1));
map.put (act2, future2 = executor.submit (act2));
map.put (act3, future3 = executor.submit (act3));
try {Thread.sleep (3000);} catch (Exception e) {}
for (Action action: map.keySet ()) {
if (action.id == 2) {
map.get (action).cancel (true);
break;
}
}
executor.shutdown ();
}
}