Java - 在某个超时期限后'继续'循环迭代

时间:2010-12-24 12:29:58

标签: java android for-loop

有一种方法可以在某个超时时间后退出('继续;')循环迭代吗?

我有一个循环,它将运行从网络收集数据,然后使用这些数据进行计算。

数据在大约1到2秒后就会过时,所以如果循环迭代时间超过1秒,那么我希望它“继续”到下一次迭代。

有时收集数据可能需要一些时间,但有时计算时间可能超过1秒,因此HTTP超时对我所需要的内容不起作用。 此外,在进行计算时,我正在使用的线程被阻止,因此我无法检查System.currentTimeMillis();

有没有办法使用另一个Thread来检查时间并强制原始for循环继续。

4 个答案:

答案 0 :(得分:4)

使用AsyncTask进行阻止计算,并且Handler属于主线程。

onPreExecute() Handler.postDelayed() Runnable AsyncTask.cancel(true) onPostExecute()调用Runnable。在您的{{1}}中,您可以取消前面提到的{{1}},因为如果计算及时完成,则不需要它。完成工作。

答案 1 :(得分:3)

我正在回答这个问题,因为我们无法更改计算代码以检查boolean stopSystem.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

计算1正在运行。 计算2正在运行。 计算3正在运行。 最新结果是:3

运行2

计算1正在运行。 计算2正在运行。 计算3正在运行。 计算4正在运行。 计算5正在运行。 最新结果是:5

运行3

计算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