: O. Yuanying

Future#cancel()を使ってみた

java.util.concurrent.Future#cancel()の意味がイマイチよくわからなかったので以下のコードを書いて試してみた。

public class CancelTest {
  public static void main(String[] args) 
    throws InterruptedException, ExecutionException {
    ExecutorService service = Executors.newFixedThreadPool(2);
    Future<String> future1 = service.submit(new WaitThread("1"));
    Future<String> future2 = service.submit(new WaitThread("2"));
    Future<String> future3 = service.submit(new WaitThread("3"));
    Future<String> future4 = service.submit(new WaitThread("4"));
        
    future4.cancel(false);
        
    System.out.println(future1.get());
    System.out.println(future2.get());
    System.out.println(future3.get());
    System.out.println(future4.get());
  }
}

class WaitThread implements Callable<String> {
  private String id = null;
  public WaitThread(String id) {
    this.id = id;
  }
  public String call() throws Exception {
    System.out.println("invoked:"+this.id);
    String rtn = "result";
    TimeUnit.SECONDS.sleep(6);
    return rtn + ":" + this.id;
  }
}

Executors.newFixedThreadPool(2)によって同時に実行されるスレッド数を2に制限してやり、WaitThreadというCallableを実装したクラスを4個流してやった。その結果以下のような標準出力が得られた。

invoked:1
invoked:2
result:1
invoked:3
result:2
result:3
Exception in thread "main" java.util.concurrent.CancellationException
	at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:203)
	at java.util.concurrent.FutureTask.get(FutureTask.java:80)
	at com.necsoft.test.CancelTest.main(CancelTest.java:36)

まず1と2がinvokeされ、1の実行が終了した瞬間に3がinvoke、4は実行されず3の結果を表示した後に4の結果を得ようとしたらCancellationExceptionが発生した。

どうやら3は実行されてないみたい。ということはcancelしたFutureは実行されないんですな~、と思いつつJavadocを参照してみたら以下のような記述がorz

このタスクの実行の取り消しを試みます。タスクが完了しているか、取り消されているか、他の何らかの理由で取り消すことができない場合、この試みは失敗します。実行の取り消しが成功し、cancel が呼び出されたときにこのタスクが開始されていない場合、このタスクは決して実行されません。タスクがすでに起動している場合、mayInterruptIfRunning パラメータは、このタスクを停止するために、タスクを実行中のスレッドに割り込みを行う必要があるかどうかを判別します。

参考資料ばかり目を通してないでちゃんとJavadocから確認しておくんだったorz