2010-05-12 33 views
10

我想第一次使用期貨。看起來很聰明,你可以取消一份工作,但它沒有按預期工作。在下面的例子中,只有第一份工作被取消。其餘完成。我誤解了對期貨的使用嗎?瞭解未來/線程

public class ThreadExample 
{ 
    public static void main(String[] args) throws InterruptedException, ExecutionException 
    { 
     int processors = Runtime.getRuntime().availableProcessors(); 
     System.out.println("Processors: " + processors); 
     ExecutorService es = Executors.newFixedThreadPool(processors); 
     int nowork = 10; 
     Future<Integer>[] workres = new Future[nowork]; 
     for(int i = 0; i < nowork; i++) 
     { 
      workres[i] = es.submit(new SomeWork(i)); 
     } 
     for(int i = 0; i < nowork; i++) 
     { 
      if(i % 2 == 0) 
      { 
       System.out.println("Cancel"); 
       workres[i].cancel(true); 
      } 
      if(workres[i].isCancelled()) 
      { 
       System.out.println(workres[i] + " is cancelled"); 
      } 
      else 
      { 
       System.out.println(workres[i].get()); 
      } 
     } 
     es.shutdown(); 
    } 
} 

class SomeWork implements Callable<Integer> 
{ 
    private int v; 
    public SomeWork(int v) 
    { 
     this.v = v; 
    } 

    @Override 
    public Integer call() throws Exception 
    { 
     TimeUnit.SECONDS.sleep(5); 
     System.out.println(v + " done at " + (new Date())); 
     return v; 
    } 
} 

輸出:

Processors: 4 
Cancel 
[email protected] is cancelled 
4 done at Wed May 12 17:47:05 CEST 2010 
2 done at Wed May 12 17:47:05 CEST 2010 
1 done at Wed May 12 17:47:05 CEST 2010 
3 done at Wed May 12 17:47:05 CEST 2010 
1 
Cancel 
2 
3 
Cancel 
4 
5 done at Wed May 12 17:47:10 CEST 2010 
7 done at Wed May 12 17:47:10 CEST 2010 
8 done at Wed May 12 17:47:10 CEST 2010 
6 done at Wed May 12 17:47:10 CEST 2010 
5 
Cancel 
6 
7 
Cancel 
8 
9 done at Wed May 12 17:47:15 CEST 2010 
9 

回答

7

問題是您的取消循環與您的get()循環重疊,該循環阻塞。我想你想要2個循環,不是嗎?一個循環取消偶數編號的作業,然後是第二個循環,檢查哪些被取消,哪些不是,然後相應地get()

它現在寫的方式,在循環甚至有機會取消workres[2]之前,它檢查並詢問workres[1]get()

所以,我認爲你需要3個階段:

1. The `submit()` loop 
2. The selective `cancel()` loop 
3. The selective `get()` loop (which blocks) 
+0

謝謝!沒有考慮get()是一種阻止問題的方法。 – 2010-05-12 16:40:50

8

Future#cancel()不會終止/中斷已經運行工作。它只會取消尚未運行的作業。

更新:polygenelubricants釘的根本原因下(+1):這裏是改進代碼:

int processors = Runtime.getRuntime().availableProcessors(); 
System.out.println("Processors: " + processors); 
ExecutorService es = Executors.newFixedThreadPool(processors); 
int nowork = 10; 
Future<Integer>[] workers = new Future[nowork]; 

for (int i = 0; i < nowork; i++) { 
    final int ii = i; 
    workers[i] = es.submit(new Callable<Integer>() { 
     public Integer call() throws Exception { 
      return ii; 
     } 
    }); 
} 

for (int i = 0; i < nowork; i++) { 
    if (i % 2 == 0) { 
     System.out.println("Cancel worker " + i); 
     workers[i].cancel(true); 
    } 
} 

for (int i = 0; i < nowork; i++) { 
    if (workers[i].isCancelled()) { 
     System.out.println("Worker " + i + " is cancelled"); 
    } else { 
     System.out.println("Worker " + i + " returned: " + workers[i].get()); 
    } 
} 

es.shutdown(); 

結果:

 
Processors: 2 
Cancel worker 0 
Cancel worker 2 
Cancel worker 4 
Cancel worker 6 
Cancel worker 8 
Worker 0 is cancelled 
Worker 1 returned: 1 
Worker 2 is cancelled 
Worker 3 returned: 3 
Worker 4 is cancelled 
Worker 5 returned: 5 
Worker 6 is cancelled 
Worker 7 returned: 7 
Worker 8 is cancelled 
Worker 9 returned: 9 

(注意,這是workers,不workres) 。

+0

「如果任務已經啓動,則mayInterruptIfRunning參數確定是否執行此任務的線程應該以試圖停止任務被中斷。」如果你只能在尚未運行的作業上使用它,Imo cancel是一個非常糟糕的單詞/方法名稱:/ – 2010-05-12 16:24:37

+0

我自己發現'cancel'和'interrupt'(或'abort'或'terminate')之間的區別。但足夠清晰。 – BalusC 2010-05-12 16:26:40

+0

您可以調用'.cancel(true)'來強制開始中斷的作業。 – Finbarr 2010-05-12 16:27:37