我有一个循环,它会运行并从网络收集数据,然后使用这些数据进行计算。
数据在约1到2秒后变得过时,因此如果循环迭代时间超过1秒,则希望它“继续”到下一次迭代。
有时收集数据可能需要时间,但有时计算可能需要超过1秒钟,因此HTTP超时对我所需的内容不起作用。 此外,在进行计算时,我使用的线程被阻塞,因此无法检查System.currentTimeMillis();
是否有一种方法可以使用另一个线程来检查时间并强制原始for循环继续。
AsyncTask
来执行阻塞计算,并拥有属于主线程的Handler
。在onPreExecute()
中,您可以Handler.postDelayed()
一个调用AsyncTask.cancel(true)
的Runnable
。在onPostExecute()
中,您可以取消上述Runnable
,因为如果计算及时完成,则不需要它。工作完成。假设无法更改计算代码以检查标志(例如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
看起来最简单的解决方案是将System.currentTimeMillis()添加到计算本身中,如果检测到运行时间过长,则无结果退出。当线程被解除阻塞时,您需要检查是否有结果,如果没有则“继续”。 当然,您可以使用另一个线程,但那可能会过度杀伤性。
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);
}
}
}
}
if(Thread.isInterrupted()){
throw new InterruptedException();
//or maybe some other code to stop processing
}
2) 做I/O操作的地方,如从套接字或文件中读取/写入通常会检查中断并抛出某种异常。可能抛出的异常类型有InterruptedIOException
、ClosedByInterruptException
等等。通常,在相应的阻塞方法的API中会指定所抛出的异常类型。在Java锁上阻塞的方法(如Queue.take()等)会抛出InterruptedException
。