java - 执行超时后返回的长时间计算

标签 java multithreading concurrency executorservice callable

我想使用迭代加深来执行搜索,这意味着每次我这样做时,我都会更深入,并且需要更长的时间。为了获得最佳结果,有时间限制(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() 是否为 true。我是否需要在 doLongComputation() 中检查线程是否已被中断?
  2. 即使我去掉了 doLongComputation(),main 方法也没有接收到 x 的值。如何确保我的程序等待 Callable“清理”并返回迄今为止最好的 x?

最佳答案

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

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

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

使用取消来停止计算并返回中间结果是行不通的,一旦取消 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();
        }
    }
}

关于java - 执行超时后返回的长时间计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35563921/

相关文章:

c++ - tbb::parallel_reduce 对比 tbb::combinable 对比 tbb::enumerable_thread_specific

java - RxJava方法从数据库读取多个条目并将它们写入多个文件

python - 同时执行多个功能

java - 我可以使用 Hibernate "createCriteria()"选择特定列吗?

java - 并发 HashMap : what's the point in locking updates only?

java - Java中如何实现多个线程下载单表数据?

ios - CoreData多线程删除

ruby - Ruby 1.9.1 中的 native 线程,对我有什么好处?

java - Java中两个字符串的交集

java - 如何使用Spring Boot将JSP文件保存在两个或多个不同的文件夹中?