在一段时间内运行代码的更好方法

时间:2011-02-09 21:53:58

标签: java timertask

我需要在预定义的时间内运行一些代码,当时间到了需要停止时。目前我正在使用TimerTask来允许代码执行一段时间,但这会导致代码创建无穷无尽的线程,而这只是效率不高。还有更好的选择吗?

当前代码;

// Calculate the new lines to draw 
            Timer timer3 = new Timer();
            timer3.schedule(new TimerTask(){
                public void run(){
                    ArrayList<String> Coords = new ArrayList<String>();
                    int x = Float.valueOf(lastFour[0]).intValue();
                    int y = Float.valueOf(lastFour[1]).intValue();
                    int x1 = Float.valueOf(lastFour[2]).intValue();
                    int y1 = Float.valueOf(lastFour[3]).intValue();
                    //Could be the wrong way round (x1,y1,x,y)?
                    Coords = CoordFiller.coordFillCalc(x, y, x1, y1);
                    String newCoOrds = "";
                    for (int j = 0; j < Coords.size(); j++)
                    {
                        newCoOrds += Coords.get(j) + " ";
                    }
                    newCoOrds.trim();
                    ClientStorage.storeAmmendedMotion(newCoOrds);

                }

            }
            ,time);

4 个答案:

答案 0 :(得分:16)

如果您使用的是Java5或更高版本,请考虑ScheduledThreadPoolExecutorFuture。使用前者,您可以计划在指定的延迟之后或以指定的时间间隔运行任务,从而更可靠地接管Timer的角色。

  

Timer工具管理延迟(“在100毫秒内运行此任务”)和定期(“每10毫秒运行此任务”)任务的执行。但是,Timer有一些缺点,ScheduledThreadPoolExecutor应该被视为替代品。 [...]

     

Timer只创建一个用于执行计时器任务的线程。如果计时器任务运行时间太长,其他TimerTask的计时准确度可能会受到影响。如果定期重复TimerTask计划每10毫秒运行而另一个TimerTask运行需要40毫秒,则重复任务(取决于它是以固定速率还是固定延迟计划)被调用四次在长时间运行的任务完成后快速连续,或完全“错过”四次调用。计划的线程池通过允许您提供多个线程来执行延迟和定期任务来解决此限制。

     

Timer的另一个问题是,如果TimerTask抛出未经检查的异常,则表现不佳。 Timer线程没有捕获异常,因此从TimerTask抛出的未经检查的异常终止了计时器线程。 Timer在这种情况下也不会复活线程;相反,它错误地假设整个Timer被取消了。在这种情况下,已经安排但尚未执行的TimerTask永远不会运行,并且无法安排新任务。

来自Java Concurrency in Practice,第6.2.5节。

最多Future s can be constrained to run指定时间(如果无法及时完成,则抛出TimeoutException。)

更新

如果您不喜欢上述内容,可以让任务测量自己的执行时间,如下所示:

int totalTime = 50000; // in nanoseconds
long startTime = System.getNanoTime();
boolean toFinish = false;

while (!toFinish) 
{
    System.out.println("Task!");
    ...
    toFinish = (System.getNanoTime() - startTime >= totalTime);
}

答案 1 :(得分:3)

  

[...]目前我正在使用TimerTask来允许代码执行一段时间[...]

计时器任务永远不会停止当前正在运行的任务。事实上,唯一的目的是一遍又一遍地重启任务。

没有与执行任务的紧密合作,没有简单的方法来解决这个问题。最好的方法是让任务监视它自己的执行,并确保它在时间结束时返回(终止)。

答案 2 :(得分:0)

如果停止你意味着程序必须退出,解决方案是为你的处理创建一个线程并将其标记为守护进程,启动它并在主线程中睡眠所需的时间,然后只需从{{ 1}}方法。

如果停止,你的意思就是停止处理。

答案 3 :(得分:0)

还应该注意,通常你只需要创建一个Timer()。从代码片段我猜你正在创建多个Timer()对象。

计划方法中的时间是运行时间,而不是运行的时间。

考虑在for循环之前设置一个开始时间&amp;如果你超过了时间限制,在for循环中休息一下。

long startedAt = System.currentTimeMillis();
long finishedCorrectly = true;
for (int j = 0; j < Coords.size(); j++) {
  newCoOrds += Coords.get(j) + " ";
  if ((System.currentTimeMillis() - startedAt) > MAX_TIME_TO_RUN) {
    finishedCorrectly = false;
    break;
  }
}