Java ExecutorServiceの使い方、その2
Java ExecutorServiceの使い方、その1の続きである。
さて、Futureのget()呼び出しは、処理が値を返すまでブロックする、つまりjoinだったわけだが、処理を中断させてjoinするにはどうすれば良いだろうか?
get()は使えない。
Futureにはcancel()というメソッドがあり、これがスレッドに割り込みをかける役割を果たしているのだが、しかし、その後でget()を使うと、例外が発生してしまう。
public static void main(String[]args) throws Exception {
ExecutorService s = Executors.newSingleThreadExecutor();
Future<?>f = s.submit(()-> {
while (!Thread.interrupted()) {
System.out.println("loop top");
try {
Thread.sleep(200);
} catch (InterruptedException ex) {
break;
}
}
});
s.shutdown();
Thread.sleep(1000);
f.cancel(true);
f.get(); // ここで例外発生。java.util.concurrent.CancellationException
}
cancelの後ではgetは使えないようだ。
うまく行く例
どうもExecutorServiceだけでは何ともできないらしい。以下のようにしてみる。
public static void main(String[]args) throws Exception {
ExecutorService s = Executors.newSingleThreadExecutor();
Semaphore sem = new Semaphore(1);
sem.acquire();
Future<?>f = s.submit(()-> {
while (!Thread.interrupted()) {
System.out.println("loop top");
try {
Thread.sleep(200);
} catch (InterruptedException ex) {
System.out.println("interrupted " + Thread.interrupted());
try {
Thread.sleep(1000);
} catch (Exception e) {}
break;
}
}
System.out.println("releasing");
sem.release();
});
s.shutdown();
Thread.sleep(1000);
f.cancel(true);
System.out.println("acquiring");
sem.acquire();
System.out.println("acquired");
}
これはうまく行く。表示は以下だ。
loop top
loop top
loop top
loop top
loop top
loop top
acauiring
interrupted false
releasing
acquired
要するにExecutorService以外の方法で何とかしなければならないらしい。