104

我在这里发现了类似的问题,但没有令我满意的答案。所以再次改写这个问题——

我有一项需要定期完成的任务(比如 1 分钟间隔)。与创建具有无限循环睡眠的新线程相比,使用 Timertask 和 Timer 执行此操作有什么优势?

使用 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,Timer 将停止执行任务,直到它到达上午 11:00,而 Thread.sleep() 方法将继续执行任务而不受阻碍。这可能是决定在这两者之间使用什么的主要决策者。

4

7 回答 7

67

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

请注意,它可以写成更短的形式以及您自己的示例:

Timer uploadCheckerTimer = new Timer(true);
uploadCheckerTimer.scheduleAtFixedRate(
    new TimerTask() {
      public void run() { NewUploadServer.getInstance().checkAndUploadFiles(); }
    }, 0, 60 * 1000);
于 2009-09-21T07:55:46.077 回答
12

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

于 2009-09-21T08:02:35.863 回答
8

Timer 文档中:

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终止计时器并丢弃任何计划任务的方法,但它不会干扰当前正在执行的任务并让它完成。但是如果计时器作为守护线程运行,那么无论我们是否取消它,它都会在所有用户线程完成执行后立即终止。

定时器与线程.sleep

定时器的使用Object.wait和它不同Thread.sleep

  1. 等待(wait)线程可以被notify另一个线程通知(使用),但睡眠线程不能,它只能被中断。
  2. 等待(和通知)必须发生在监视器对象上同步的块中,而睡眠则不会。
  3. 虽然 sleep 不会释放锁,但 waiting 会为调用等待的对象释放锁。
于 2018-09-13T04:01:36.573 回答
5

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

于 2011-10-03T03:40:08.440 回答
4

有一个关键论点反对使用 Java 线程和sleep方法管理此任务。您正在使用while(true)无限期地停留在循环中并通过进入睡眠状态来休眠线程。如果NewUploadServer.getInstance().checkAndUploadFiles();占用一些同步资源怎么办。其他线程将无法访问这些资源,可能会发生饥饿,这会减慢整个应用程序的速度。这些类型的错误很难诊断,最好防止它们的存在。

另一种方法触发对您重要的代码的执行,即NewUploadServer.getInstance().checkAndUploadFiles();通过调用run()您的方法TimerTask同时让其他线程使用资源。

于 2009-09-21T08:25:50.840 回答
4

如果你线程得到异常并被杀死,那就是一个问题。但是 TimerTask 会处理它。无论之前的运行是否失败,它都会运行。

于 2014-02-06T19:45:48.430 回答
2

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

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

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

于 2014-11-20T03:24:48.613 回答