9

我需要在预定义的时间内运行一些代码,当时间到时它需要停止。目前我正在使用 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

4 回答 4

17

如果您使用的是 Java5 或更高版本,请考虑ScheduledThreadPoolExecutor使用Future. 使用前者,您可以安排任务在指定的延迟后或以指定的时间间隔运行,因此它接管了 的角色Timer,只是更可靠。

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

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

另一个问题Timer是,如果 aTimerTask抛出未经检查的异常,它的行为就会很差。Timer线程不会捕获异常,因此从 a 抛出的未经检查的异常会终止TimerTask计时器线程。Timer在这种情况下也不会复活线程;相反,它错误地假设整个Timer被取消了。这种情况下,TimerTask已经调度但还没有执行的s永远不会运行,也无法调度新的任务。

来自Java Concurrency in Practice,第 6.2.5 节。

并且Futures可以被限制为最多运行指定的时间(TimeoutException如果它不能及时完成,则抛出 a)。

更新

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

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

while (!toFinish) 
{
    System.out.println("Task!");
    ...
    toFinish = (System.getNanoTime() - startTime >= totalTime);
}
于 2011-02-09T22:02:34.300 回答
4

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

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

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

于 2011-02-09T21:57:54.393 回答
0

如果停止意味着程序必须退出,解决方案是为您的处理创建一个线程并将其标记为守护进程,启动它并在主线程中休眠所需的时间,然后简单地从该main()方法返回。

从头开始,如果停止,您的意思只是停止处理。

于 2011-02-09T22:01:49.733 回答
0

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

schedule 方法中的时间是运行的时间,而不是运行多长时间。

如果您超过了时间限制,请考虑在 for 循环之前放置一个开始时间并在 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;
  }
}
于 2011-02-09T22:21:12.520 回答