2010年3月6日土曜日

ThreadPoolExecutor について(第1部:基本的な使い方)

本当に基本的な使い方を紹介します。

■前提条件
スレッド数:3
スレッド消失時間:500ms
スレッド実行される処理(タスク)はRunnableインタフェースを実装させます。
(Callableインタフェースでもできます(タスクの登録方法がRunnableと若干異なります))

■実ソース

package sample.thread.basic;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class SampleMain {

public static void main(final String[] args) {
new SampleMain().go();
}

public void go() {
System.out.println("処理開始");
final BlockingQueue<Runnable%gt; queue = new LinkedBlockingQueue]<Runnable>();
// queueに事前に積んでおくこともできる
for (int i = 0; i < 50; i++) {
queue.add(new TestRunnable());
}
final ThreadPoolExecutor tpe = new ThreadPoolExecutor(3, 3, 500, TimeUnit.MILLISECONDS, queue, new ThreadPoolExecutor.CallerRunsPolicy());
try {
// shutdown()を呼ぶ前であれば、タスクを後から追加することもできる
for (int i = 0; i < 50; i++) {
tpe.execute(new TestRunnable());
}
} finally {
// 必ずshutdownを実行する。実行しないとスレッドが開放されないので処理が一生
System.out.println("ShutDown実行。");
tpe.shutdown();
}
while (true) {
if (tpe.isTerminated()) {
break;
}
try {
System.out.println("タスク終了待ち 1000ms.");
Thread.currentThread();
Thread.sleep(1000);
} catch (InterruptedException ignore) {
}
}
System.out.println("処理終了");
}

/**
* スレッド実行されるタスク。
*/
private static class TestRunnable implements Runnable {

private static volatile int count = 0;

@Override
public void run() {
System.out.println(count++);
}
}
}


■気をつける点
必ずshutdown()メソッドを呼ぶ必要があります!
これを忘れるとMainスレッドが終了してもスレッドだけプーリングされている状態となり、処理が終わりません。
shutdown()メソッドを実行してもすぐに処理が終了するわけではありません。
すべてのスレッドを正常に処理し終えるまでスレッドは開放されません。
すべてのタスクの処理が終わるのを待ちたいのであれば、終了を待つ必要があります。

ThreadPoolExecutor.terminated()をオーバーライドして、終了処理を書くこともできます。


こんな簡単な記述で、スレッドをプーリングすることができます。
次回は、ThreadPoolExecutorをインスタンス化する際に指定できる、いろいろな機能について触れたいと思います。

0 件のコメント:

コメントを投稿