2014-01-23 72 views
4

我剛注意到以下現象時取消由ForkJoinPool返回的Future。給定以下示例代碼:ForkJoinPool重置線程中斷狀態

ForkJoinPool pool = new ForkJoinPool(); 
Future<?> fut = pool.submit(new Callable<Void>() { 

    @Override 
    public Void call() throws Exception { 
    while (true) { 
     if (Thread.currentThread().isInterrupted()) { // <-- never true 
     System.out.println("interrupted"); 
     throw new InterruptedException(); 
     } 
    } 
    } 
}); 

Thread.sleep(1000); 
System.out.println("cancel"); 
fut.cancel(true); 

該程序從不打印interrupted。的ForkJoinTask#cancel(boolean)文檔說:

mayInterruptIfRunning - 這個值默認執行沒有影響,因爲中斷將不被用於控制抵消。

如果ForkJoinTasks忽略中斷,您還應該如何檢查提交給ForkJoinPool的可加密內部的取消?

+0

順便說一句,你爲什麼在這種情況下使用FJP? – Mikhail

+0

@Mikhail這只是我們用例的一個非常簡單的例子。我們在可調用函數中啓動一些RecursiveActions,並在ForkJoinTask.getPool() – Korbi

回答

5

這是因爲Future<?>ForkJoinTask.AdaptedCallable延伸ForkJoinTask,它的取消方法是:

public boolean cancel(boolean mayInterruptIfRunning) { 
    return setCompletion(CANCELLED) == CANCELLED; 
} 

private int setCompletion(int completion) { 
    for (int s;;) { 
     if ((s = status) < 0) 
      return s; 
     if (UNSAFE.compareAndSwapInt(this, statusOffset, s, completion)) { 
      if (s != 0) 
       synchronized (this) { notifyAll(); } 
      return completion; 
     } 
    } 
} 

它沒有做任何干擾,它只是設置狀態。我想這是因爲ForkJoinPoolsFuture可能有一個非常複雜的樹結構,並且不清楚按照何種順序來取消它們。

+0

上調用,感謝Mikhail的調查。看起來像沒有辦法檢查Callable中的取消。我需要提交一個ForkJoinTask並調用isCancelled(),這很糟糕,因爲你總是需要傳遞一個引用到ForkJoinTask來檢查取消 – Korbi