有一种方法可以在某个超时时间后退出('继续;')循环迭代吗?
我有一个循环,它将运行从网络收集数据,然后使用这些数据进行计算。
数据在大约1到2秒后就会过时,所以如果循环迭代时间超过1秒,那么我希望它“继续”到下一次迭代。
有时收集数据可能需要一些时间,但有时计算时间可能超过1秒,因此HTTP超时对我所需要的内容不起作用。 此外,在进行计算时,我正在使用的线程被阻止,因此我无法检查System.currentTimeMillis();
有没有办法使用另一个Thread来检查时间并强制原始for循环继续。
答案 0 :(得分:4)
使用AsyncTask
进行阻止计算,并且Handler
属于主线程。
在onPreExecute()
Handler.postDelayed()
Runnable
AsyncTask.cancel(true)
onPostExecute()
调用Runnable
。在您的{{1}}中,您可以取消前面提到的{{1}},因为如果计算及时完成,则不需要它。完成工作。
答案 1 :(得分:3)
我正在回答这个问题,因为我们无法更改计算代码以检查boolean stop
或System.currentTimeMillis()
等标记。如果这是真的,那么这是一个可能的解决方案。
每当您期望获得新结果时,您需要做的是生成一个新计算。我所包含的这个程序确实存在一些问题,例如从未确保计算完成,导致无限数量的线程。同样,这是基于您无法提前停止计算的假设。如果你有这个选项,你可以在计算循环中设置一个标志,以便提前退出方法。
我不知道为什么我无法让代码样式正常工作,我是这个网站的新手,任何帮助都会受到赞赏
您将维护一堆已处理的结果。如果您始终获得最佳结果,那么它将是您可以在该时间点处理的最新结果。我在这里创建一个堆栈的原因,而不是仅仅过度编写之前的结果,这是因为你需要对之前的计算做一些事情。
在我的示例中,performCalculation
的正文对于模拟您提到的环境非常重要。
您可以创建新线程,或使用现有线程持续处理投放到results
的结果。
import java.util.Random;
import java.util.Stack;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;
public class Main
{
private static int CALCULATION_THRESHOLD = 2000;
private static Stack<Object> results = new Stack<Object>();
private static Object resultTrigger = new Object();
public static void main(String[] args)
{
Timer calculationTimer = new Timer(true);
calculationTimer.schedule(new TimerTask() {
@Override
public void run()
{
Thread calculationThread = new Thread() {
public void run() {
Object result = performCalculation();
results.push(result);
synchronized(resultTrigger) {
resultTrigger.notifyAll();
}
}
};
calculationThread.start();
}
}, CALCULATION_THRESHOLD, CALCULATION_THRESHOLD);
synchronized(resultTrigger) {
if (results.isEmpty()) {
// This is bad as it will never end if you don't
// get a result, add a timeout here.
try { resultTrigger.wait(); }
catch (InterruptedException ex) {}
}
}
// Get the next result
Object result = results.pop();
System.out.println ("Latest result is : " + result);
// Do something with the remaining results or throw
// them away
results.clear();
}
private static AtomicInteger counter = new AtomicInteger();
// This is the method we are assuming can't be
// changed to check for a stop flag.
public static Object performCalculation()
{
int calcID = counter.addAndGet(1);
System.out.println ("Calculation " + calcID + " is running.");
Random randomGenerator = new Random();
int sleep = randomGenerator.nextInt(10000);
// Ensure we sleep for at least 2 seconds
try { Thread.sleep(sleep + 2000); }
catch (InterruptedException ex) {}
return String.valueOf(counter.get());
}
}
示例输出:
计算1正在运行。 计算2正在运行。 计算3正在运行。 最新结果是:3
计算1正在运行。 计算2正在运行。 计算3正在运行。 计算4正在运行。 计算5正在运行。 最新结果是:5
计算1正在运行。 计算2正在运行。 最新结果是:2
答案 2 :(得分:1)
似乎最简单的解决方案是将System.currentTimeMillis()添加到计算本身,如果它检测到它运行太长而无法退出而没有结果。当线程被解除阻塞时,你必须检查是否有结果,如果没有“继续”。 当然,你可以使用另一个线程,但这将是一个过度杀伤。
答案 3 :(得分:0)
我建议使用提交给Callable
的{{1}}任务,然后暂停运行。代码应该非常直观:
ExecutorService
为了使其完美运行,您的数据收集任务将需要检查线程中断。这主要包括:
1)检查可能长时间使用CPU的循环内部的线程中断(这不包括I / O)。如果您有大型循环进行繁重处理,请确保此代码以相对较短的间隔运行
import java.util.concurrent.*;
class InterruptibleProcessing{
public static void main(String[] args){
ExecutorService es = Executors.newSingleThreadExecutor();
//the loop
for(int i=0; i<iterations; i++){
//run your data gathering process in a separate thread
Future<Result> futureResult = es.submit(new Callable<Result>(){
public Result call(){
//do you work here and return the result
return gatherData();
}
});
try{
//wait for result with timeout
Result result = futureResult.get(1, TimeUnit.SECONDS);
//if we are here then we have the result in less than 1 second
// do something and exit the loop
break;
}catch(TimeoutException timeout){
//Didn't finish in time, cancel the task, and proceed to
//next iteration. This will send an interrupt signal to
//your task thread.
futureResult.cancel(true);
}
}
}
}
2)执行I / O的地方,例如从套接字或文件读取/写入,通常会检查中断并抛出某种异常。异常类型可能是if(Thread.isInterrupted()){
throw new InterruptedException();
//or maybe some other code to stop processing
}
,InterruptedIOException
等等。抛出的异常类型通常在相应阻塞方法的API中指定。阻止Java锁定的方法(如Queue.take()等)将抛出ClosedByInterruptException
。