Java 如何在单独的线程中运行特定时间量的任务并返回结果?

Java 如何在单独的线程中运行特定时间量的任务并返回结果?,java,time,concurrency,Java,Time,Concurrency,如何在特定的时间内运行线程,并在时间流逝时返回一些结果 到目前为止,我能想到的最佳解决方案是手动测量时间。但也许有更优雅的开箱即用的解决方案 我有一个算法,在每次迭代中都会改进以前的解决方案。我想在一个单独的线程中运行这段代码,运行时间是预定义的。当时间流逝时,应返回最佳(最新)解决方案 因为我想返回解决方案,所以不能只使用-它会导致TimeoutException。从“控制”线程中断一段时间后中断线程也是如此-在这种情况下,Future将被取消并返回null 我目前的解决办法如下: 定时器逻辑

如何在特定的时间内运行线程,并在时间流逝时返回一些结果

到目前为止,我能想到的最佳解决方案是手动测量时间。但也许有更优雅的开箱即用的解决方案

我有一个算法,在每次迭代中都会改进以前的解决方案。我想在一个单独的线程中运行这段代码,运行时间是预定义的。当时间流逝时,应返回最佳(最新)解决方案

因为我想返回解决方案,所以不能只使用-它会导致
TimeoutException
。从“控制”线程中断一段时间后中断线程也是如此-在这种情况下,
Future
将被取消并返回
null

我目前的解决办法如下:

定时器逻辑:

private class ExecutionTimer {

    private final long executionTimeLimit;

    private long startTime;

    // accepts execution time limit in _miliseconds_
    public ExecutionTimer(final int executionTimeLimit) {
        this.executionTimeLimit = TimeUnit.MILLISECONDS.toNanos(executionTimeLimit);
    }

    public void start() {
        this.startTime = System.nanoTime();
    }

    public boolean hasElapsed() {
        return (System.nanoTime() - startTime) >= executionTimeLimit;
    }
}
…和工作线程:

 private class WorkerThread implements Callable<Double> {

        private final ExecutionTimer executionTimer;

        public WorkerThread(final int executionTimeLimit) {
            this.executionTimer = new ExecutionTimer(executionTimeLimit);
        }

        @Override
        public Double call() throws Exception {
            executionTimer.start();

            double partialSolution = 0;
            while (!executionTimer.hasElapsed()) {
                // let's imagine that here solution is improved ;)
                partialSolution = new Random().nextDouble(); 
            }
            return partialSolution;
        }
    }
私有类WorkerThread实现可调用{
私有最终执行计时器ExecutionTimer;
公共WorkerThread(最终int executionTimeLimit){
this.executionTimer=新的executionTimer(executionTimeLimit);
}
@凌驾
public Double call()引发异常{
executionTimer.start();
双部分解=0;
而(!executionTimer.hasExpressed()){
//让我们想象一下,这里的解决方案得到了改进;)
partialSolution=新的Random().nextDouble();
}
返回部分解;
}
}
编辑:
工作线程可以无限期地工作,而不会从外部中断它-这很好,因为算法总是可以改进以前的解决方案(当然,在一些显著的时间改进相对较小之后)

您可以将中间结果存储在共享的线程安全变量中(例如,在您的情况下,
volatile double
)-当未来超时时,您可以从该变量中检索最新的计算值

换言之:

  • 如果
    future.get(…)
    返回一个值,请使用它
  • 如果您得到一个
    TimeoutException
    ,请通过调用
    yourWorkerThread.getLatestValue();
    来检索该值,该函数返回一个
    易失性的双最晚值
    ,该值在每个循环中更新,而不是在本地
    部分解决方案

或者,指向Guava库和其他解决方案(这都归结为我在评论中讨论的两个选项)。请注意,使用带超时的future。

您可以将中间结果存储在共享的线程安全变量中(例如,在您的情况下,
volatile double
)-当未来超时时,您可以从该变量中检索最新的计算值

换言之:

  • 如果
    future.get(…)
    返回一个值,请使用它
  • 如果您得到一个
    TimeoutException
    ,请通过调用
    yourWorkerThread.getLatestValue();
    来检索该值,该函数返回一个
    易失性的双最晚值
    ,该值在每个循环中更新,而不是在本地
    部分解决方案

或者,指向Guava库和其他解决方案(这都归结为我在评论中讨论的两个选项)。请注意,使用带超时的future。

您可以使用正常future.get(),它会无限期地等待。

您可以使用正常future.get(),它会无限期地等待。

我建议采用生产者-消费者模式:

负责培养结果的算法不断产生新的更好的结果,并将它们放入共享的线程安全资源中

对该结果感兴趣的客户机在每个预定义的时间间隔(设置为问题中的超时)使用该资源

资源本身可以是流(例如BlockingQueue)或单个变量


它的优点是很容易推理,它定义了清晰的边界,并且非常灵活。例如:只要没有结果,客户端就可以阻止,或者只要没有新的和改进的结果,客户端就可以阻止。生产者-消费者模式的所有变体,只要调整生产者通知条件即可

我建议采用生产者-消费者模式:

负责培养结果的算法不断产生新的更好的结果,并将它们放入共享的线程安全资源中

对该结果感兴趣的客户机在每个预定义的时间间隔(设置为问题中的超时)使用该资源

资源本身可以是流(例如BlockingQueue)或单个变量

它的优点是很容易推理,它定义了清晰的边界,并且非常灵活。例如:只要没有结果,客户端就可以阻止,或者只要没有新的和改进的结果,客户端就可以阻止。生产者-消费者模式的所有变体,只要调整生产者通知条件即可

考虑使用&

import java.util.TimerTask;
导入java.util.concurrent.Callable;
导入java.util.concurrent.AtomicBoolean;
公共类解算器实现了可调用{
private final AtomicBoolean running=新的AtomicBoolean(true);
公共停车场(){
this.running.set(true);
}
@凌驾
public Double call()引发异常{
双答案=空;
while(this.running.get()){
答案=keepimproviding();
}
//TODO自动生成的方法存根
返回答案;
}
}
类Schedular扩展了TimerTask{
私人最终解决方案;
公共调度(解算器){
this.solver=solver;
}
@凌驾
公开募捐{
this.solver.stop();
}
}
使用下面的方法

final Solver solver = new Solver();
Schedular schedular = new Schedular(solver);
final Timer timer = new Timer();
timer.schedule(schedular, 0, TimeUnit.MINUTES.toMillis(1));

ExecutorService executor = // get a executor somehow
final Future<Double> future = executor.submit(solver);
final Double answer = future.get();
System.out.println(answer);
final Solver=new Solver();
附表
final Solver solver = new Solver();
Schedular schedular = new Schedular(solver);
final Timer timer = new Timer();
timer.schedule(schedular, 0, TimeUnit.MINUTES.toMillis(1));

ExecutorService executor = // get a executor somehow
final Future<Double> future = executor.submit(solver);
final Double answer = future.get();
System.out.println(answer);