2016-02-22 33 views
1

我想使用迭代深化來執行搜索,這意味着每次執行搜索時,我都會更深入,這需要更長的時間。有一個時間限制(2秒)以獲得最佳結果。從我研究的內容來看,最好的方法是使用ExecutorService,一個Future,並在時間用完時中斷它。這是我的時刻:執行超時後返回的長計算

在我的主要功能:

ExecutorService service = Executors.newSingleThreadExecutor(); 
ab = new AB(); 
Future<Integer> f = service.submit(ab); 
Integer x = 0; 
try { 
    x = f.get(1990, TimeUnit.MILLISECONDS); 
} 
catch(TimeoutException e) { 
    System.out.println("cancelling future"); 
    f.cancel(true); 
} 
catch(Exception e) { 
    throw new RuntimeException(e); 
} 
finally { 
    service.shutdown(); 
} 
System.out.println(x); 

而可贖回:

public class AB implements Callable<Integer> { 

    public AB() {} 

    public Integer call() throws Exception { 
     Integer x = 0; 
     int i = 0; 
     while (!Thread.interrupted()) { 
      x = doLongComputation(i); 
      i++; 
     } 
     return x; 
    } 
} 

我有兩個問題:

  1. doLongComputation()沒有被打斷,程序只會在完成工作後檢查Thread.interrupted()是否爲真。我是否需要在doLongComputation()中放入檢查來查看線程是否被中斷?
  2. 即使我擺脫了doLongComputation(),主要方法並沒有收到x的值。我如何確保我的程序等待Callable「清理」並返回迄今爲止最好的x?

回答

2

要回答第1部分:是的,您需要讓您的長期任務檢查中斷標誌。中斷需要被中斷的任務合作。

此外,你應該使用Thread.currentThread().isInterrupted(),除非你特別想清除中斷標誌。拋出(或重新拋出)的代碼InterruptedException使用Thread#interrupted作爲檢查標誌並將其清除的便捷方式,當您編寫Runnable或Callable時,這通常不是您想要的。

現在回答第2部分:取消不是你想要的。

使用取消來停止計算並返回中間結果不起作用,一旦取消將來,您將無法從get方法中檢索返回值。你可以做的是使計算的每一個細化都成爲它自己的任務,這樣你就可以提交一個任務,獲得結果,然後以結果作爲起點提交下一個任務,隨時保存最新結果。

這裏是我想出的一個例子來演示這個,用牛頓法計算平方根的連續近似值。每次迭代是一個單獨的任務,當前一個任務完成時,它將被提交(使用先前任務的近似值):

import java.util.concurrent.*; 
import java.math.*; 

public class IterativeCalculation { 

    static class SqrtResult { 
     public final BigDecimal value; 
     public final Future<SqrtResult> next; 
     public SqrtResult(BigDecimal value, Future<SqrtResult> next) { 
      this.value = value; 
      this.next = next; 
     } 
    } 

    static class SqrtIteration implements Callable<SqrtResult> { 
     private final BigDecimal x; 
     private final BigDecimal guess; 
     private final ExecutorService xs; 
     public SqrtIteration(BigDecimal x, BigDecimal guess, ExecutorService xs) { 
      this.x = x; 
      this.guess = guess; 
      this.xs = xs; 
     } 

     public SqrtResult call() { 
      BigDecimal nextGuess = guess.subtract(guess.pow(2).subtract(x).divide(new BigDecimal(2).multiply(guess), RoundingMode.HALF_EVEN)); 
      return new SqrtResult(nextGuess, xs.submit(new SqrtIteration(x, nextGuess, xs))); 
     } 
    } 

    public static void main(String[] args) throws Exception { 
     long timeLimit = 10000L; 
     ExecutorService xs = Executors.newSingleThreadExecutor(); 
     try { 
      long startTime = System.currentTimeMillis(); 
      Future<SqrtResult> f = xs.submit(new SqrtIteration(new BigDecimal("612.00"), new BigDecimal("10.00"), xs)); 
      for (int i = 0; System.currentTimeMillis() - startTime < timeLimit; i++) { 
       f = f.get().next;     
       System.out.println("iteration=" + i + ", value=" + f.get().value); 
      } 
      f.cancel(true); 
     } finally { 
      xs.shutdown(); 
     } 
    } 
} 
+0

謝謝!對於第2部分,我的問題是'f.cancel(true)'不僅中斷了線程,而且完全取消了它。所以AB永遠不會到達'return x'。 – acornellier

+0

@ user3389645:我明白你的意思了。取消可能不是你想要的。 –