java.util.concurrent.ScheduledExecutorService
何かそれなりに重い処理が色々あったとする。バッチ的なアレとか。
で、処理は大体がアトミックで、スレッドプールを使って、それぞれを処理する事で、処理効率を稼ぎたい時に使うAPI。
Javadocを見てても良く分からんくて、ハマったので、実装例をばメモ。
このコードの内容は、
処理は重くていつ終わるか分からない上に、処理中に更に新しいタスクを積んでしまうので、 全体として、本当にいつ終わるか分からないので、 プロセスを起動した後、一定の時間が経過したら、それ以上タスクを積めない様にしつつ、 プロセスを綺麗に終了する。
という感じ。
import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class Heavy { protected ScheduledExecutorService executorService; public Heavy() { } public void initialize() { this.executorService = Executors.newScheduledThreadPool(5); this.executorService.schedule(new Runnable() { @Override public void run() { executorService.shutdown(); } }, 3, TimeUnit.MINUTES); // 3分後にシャットダウン開始。 } public void execute() { this.executorService.schedule(new Runnable() { @Override public void run() { // スゲェ重い処理。 execute(); // 再処理 } }, 0, TimeUnit.MILLISECONDS); } public void dispose() { try { this.executorService.awaitTermination(4, TimeUnit.MINUTES); } catch (InterruptedException e) { e.printStackTrace(); } } public static void main(String[] args) { Heavy me = new Heavy(); try { me.initialize(); // 処理をキューイングする。 me.execute(); me.execute(); me.execute(); me.execute(); } finally { me.dispose(); } } }
ポイントは、
- ExecutorService#shutdownを呼ぶRunnableを最初にscheduleしておく事
- shutdownキューが実行されるであろうより後に、実行されるようにExecutorService#awaitTerminationを呼ぶ事。
- awaitTerminationは、設定した時間が経過するまでは、処理がブロックさりる事が重要。