Java 执行超时后返回的长计算

Java 执行超时后返回的长计算,java,multithreading,concurrency,executorservice,callable,Java,Multithreading,Concurrency,Executorservice,Callable,我希望使用迭代深化来执行搜索,这意味着每次我这样做时,我都会进行更深的搜索,而且需要更长的时间。要获得可能的最佳结果,有一个时间限制(2秒)。根据我的研究,最好的方法是使用ExecutorService,一个未来,并在时间用完时中断它。这就是我目前的情况: 在我的主要职能中: ExecutorService service = Executors.newSingleThreadExecutor(); ab = new AB(); Future<Integer> f = service

我希望使用迭代深化来执行搜索,这意味着每次我这样做时,我都会进行更深的搜索,而且需要更长的时间。要获得可能的最佳结果,有一个时间限制(2秒)。根据我的研究,最好的方法是使用ExecutorService,一个未来,并在时间用完时中断它。这就是我目前的情况:

在我的主要职能中:

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);
ExecutorService service=Executors.newSingleThreadExecutor();
ab=新的ab();
未来f=服务提交(ab);
整数x=0;
试一试{
x=f.get(1990,时间单位为毫秒);
}
捕获(超时异常e){
System.out.println(“取消未来”);
f、 取消(真);
}
捕获(例外e){
抛出新的运行时异常(e);
}
最后{
service.shutdown();
}
系统输出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;
    }
}
public类AB实现了可调用{
公共AB(){}
公共整数调用()引发异常{
整数x=0;
int i=0;
而(!Thread.interrupted()){
x=多龙计算(i);
i++;
}
返回x;
}
}
我有两个问题:

  • doLongComputation()没有被中断,程序只在完成工作后检查Thread.interrupted()是否为true。我是否需要在dolongcompulation()中进行检查以查看线程是否被中断
  • 即使我去掉了dolongcompulation(),main方法也不会接收x的值。如何确保我的程序等待可调用程序“清理”并返回迄今为止最好的x

  • 要回答第1部分:是的,您需要让长任务检查中断标志。中断需要被中断任务的配合

    此外,您还应该使用
    Thread.currentThread().isInterrupted()
    ,除非您特别想清除中断标志。抛出(或重试)InterruptedException的代码使用Thread#interrupted作为检查标志和清除标志的便捷方式,当您编写可运行或可调用的代码时,这通常不是您想要的

    现在回答第二部分:取消不是你想要的

    使用cancellation停止计算并返回中间结果不起作用,一旦取消future,就无法从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();
            }
        }
    }
    
    import java.util.concurrent.*;
    导入java.math.*;
    公共类迭代计算{
    静态类SqrtResult{
    公共最终大十进制值;
    下一步将公布最终结果;
    公共SqrtResult(BigDecimal值,未来下一个){
    这个值=值;
    this.next=next;
    }
    }
    静态类SqrtIteration实现可调用{
    私有最终大十进制x;
    私人最终猜测;
    私人最终执行人服务xs;
    公共SQR迭代(BigDecimal x、BigDecimal guess、ExecutorService xs){
    这个.x=x;
    this.guess=猜测;
    this.xs=xs;
    }
    公共SqrtResult调用(){
    BigDecimal nextGuess=guess.subtract(guess.pow(2)、subtract(x)、divide(新的BigDecimal(2)、multiply(guess)、RoundingMode.HALF_偶数));
    返回新的SqrtResult(nextGuess,xs.submit)(新的sqrteration(x,nextGuess,xs));
    }
    }
    公共静态void main(字符串[]args)引发异常{
    长时间限制=10000升;
    ExecutorService xs=Executors.newSingleThreadExecutor();
    试一试{
    long startTime=System.currentTimeMillis();
    Future f=xs.submit(新的sqrteration(新的BigDecimal(“612.00”)、新的BigDecimal(“10.00”)、xs);
    对于(int i=0;System.currentTimeMillis()-startTime
    谢谢!对于第2部分,我的问题是
    f.cancel(true)
    不仅中断了线程,而且完全取消了它。所以AB永远不会到达
    return x
    @user3389645:我明白你的意思了。取消可能不是你想要的。