定时器和; TimerTask vs Thread +在Java中休眠

时间:2009-09-21 07:47:45

标签: java timer while-loop sleep task

我在这里发现了类似的问题,但没有我满意的答案。所以再次重新提出这个问题 -

我有一项需要定期完成的任务(比如间隔1分钟)。使用Timertask& amp;定时器执行此操作而不是创建具有无限循环睡眠的新线程?

使用timertask的代码段 -

TimerTask uploadCheckerTimerTask = new TimerTask(){

 public void run() {
  NewUploadServer.getInstance().checkAndUploadFiles();
 }
};

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(uploadCheckerTimerTask, 0, 60 * 1000);

使用Thread和sleep的代码片段 -

Thread t = new Thread(){
 public void run() {
  while(true) {
   NewUploadServer.getInstance().checkAndUploadFiles();
   Thread.sleep(60 * 1000);
  }
 }
};
t.start();

如果逻辑执行时间超过间隔时间,我真的不必担心是否会错过某些周期。

请对此发表评论..

更新:
最近我发现使用Timer与Thread.sleep()之间存在另一个区别。假设当前系统时间是上午11:00。如果由于某种原因我们将系统时间回滚到上午10:00,则计时器将停止执行任务,直到它到达上午11:00,而Thread.sleep()方法将继续执行任务而不受阻碍。这可能是决定在这两者之间使用什么的主要决策者。

7 个答案:

答案 0 :(得分:66)

TimerTask的优点在于它更好地表达了您的意图(即代码可读性),并且已经实现了cancel()功能。

请注意,它可以用更短的形式和您自己的示例编写:

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(
    new TimerTask() {
      public void run() { NewUploadServer.getInstance().checkAndUploadFiles(); }
    }, 0, 60 * 1000);

答案 1 :(得分:13)

Timer / TimerTask还会考虑任务的执行时间,因此它会更准确一些。它更好地处理多线程问题(例如避免死锁等)。当然,使用经过充分测试的标准代码而不是一些自制的解决方案通常会更好。

答案 2 :(得分:5)

我不知道为什么但是我正在编写的程序正在使用Timers并且它的堆大小不断增加,一旦我将其更改为线程/睡眠问题已解决。

答案 3 :(得分:4)

如果你的线程获得异常并被杀死,那就是一个问题。 但TimerTask会照顾它。无论以前的运行失败,它都会运行。

答案 4 :(得分:3)

使用Java线程和sleep方法管理此任务有一个重要的论点。您正在使用while(true)无限期地保持循环并通过进入休眠状态来休眠线程。如果NewUploadServer.getInstance().checkAndUploadFiles();占用了一些同步资源,该怎么办?其他线程将无法访问这些资源,可能会发生饥饿,这可能会降低整个应用程序的速度。这些错误很难诊断,防止它们存在是个好主意。

另一个aproach触发执行对您很重要的代码,即NewUploadServer.getInstance().checkAndUploadFiles();通过调用run()的{​​{1}}方法,同时允许其他线程使用资源。

答案 5 :(得分:3)

来自Timer documentation

  

Java 5.0引入了java.util.concurrent软件包,其中之一是   其中的并发实用程序是ScheduledThreadPoolExecutor   是用于以给定速率重复执行任务的线程池,或者   延迟。实际上,它是多功能的替代品   Timer / TimerTask组合,因为它允许多个服务线程,   接受各种时间单位,不需要子类化TimerTask   (只需实现Runnable)。配置ScheduledThreadPoolExecutor   一个线程使它等效于Timer。

因此更喜欢ScheduledThreadExecutor而不是Timer

  • Timer使用单个后台线程,该线程用于依次执行所有计时器任务。因此,任务应快速完成,否则会延迟后续任务的执行。但是,在ScheduledThreadPoolExecutor的情况下,我们可以配置任意数量的线程,还可以通过提供ThreadFactory来完全控制。
  • Timer由于使用Object.wait(long)方法而对系统时钟敏感。但是ScheduledThreadPoolExecutor不是。
  • TimerTask中抛出的运行时异常将杀死该特定线程,从而使Timer死机,因为我们可以在ScheduledThreadPoolExecutor中处理该异常,从而不会影响其他任务。
  • Timer提供了cancel方法来终止计时器并丢弃所有计划的任务,但是它不会干扰当前正在执行的任务并使其完成。但是,如果timer作为守护程序线程运行,则无论我们是否取消它,它都会在所有用户线程完成执行后立即终止。

计时器与Thread.sleep

计时器使用Object.wait,它与Thread.sleep

不同
  1. 一个正在等待的(wait)线程可以由另一个线程通知(使用notify),但是一个休眠的线程不能被通知,只能被中断。
  2. 等待(并通知)必须在监视对象上同步的块中发生,而睡眠则不必。
  3. 虽然睡眠不释放锁,但是等待将释放被调用对象的锁。

答案 6 :(得分:1)

我想我理解你的问题,我看到一些非常相似的东西。我有定时器,有的每30分钟,有的每隔几天。从我读到的内容和我看到的评论看来,垃圾收集看起来永远不会运行,因为所有任务都永远不会完成。我认为垃圾收集会在计时器处于睡眠状态时运行,但我没有看到它,并且根据文档没有看到它。

我认为产生新线程完成并允许垃圾收集。

有人请证明我错了,重写我遗传的东西会很痛苦。