286

我有代码,我使用java.util.Timer. 我环顾四周,看到ExecutorService可以做同样的事情。所以这里的这个问题,你有没有使用TimerExecutorService安排任务,一个使用比另一个有什么好处?

还想检查是否有人使用过该Timer课程并遇到ExecutorService为他们解决的任何问题。

4

7 回答 7

340

根据实践中的Java并发

  • Timer可以对系统时钟的变化敏感,ScheduledThreadPoolExecutor不是。
  • Timer只有一个执行线程,所以长时间运行的任务会延迟其他任务。ScheduledThreadPoolExecutor可以配置任意数量的线程。此外,如果需要(通过提供ThreadFactory),您可以完全控制创建的线程。
  • 抛出的运行时异常TimerTask杀死一个线程,从而使Timer死:-( ... 即计划任务将不再运行。ScheduledThreadExecutor不仅捕获运行时异常,而且它允许您在需要时处理它们(通过覆盖afterExecute方法 from ThreadPoolExecutor)。任务抛出的异常将被取消,但其他任务将继续运行。

如果您可以使用ScheduledThreadExecutor代替Timer,请这样做。

还有一件事......虽然ScheduledThreadExecutor在 Java 1.4 库中不可用,但有一个JSR 166 ( java.util.concurrent) 到 Java 1.2, 1.3, 1.4的反向移植,它具有ScheduledThreadExecutor类。

于 2009-01-03T22:22:53.493 回答
66

如果您可以使用它,那么很难想出使用 Java 5 执行器框架的理由。来电:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

将为您提供ScheduledExecutorServiceTimer(即它将是单线程的)类似的功能,但其访问可能更具可扩展性(在后台,它使用并发结构而不是与Timer类完全同步)。使用 aScheduledExecutorService还可以为您带来以下优势:

  • 如果需要,您可以自定义它(参见newScheduledThreadPoolExecutor()ScheduledThreadPoolExecutor类)
  • “一次性”执行可以返回结果

Timer关于我能想到的坚持的唯一原因是:

  • 它在 Java 5 之前可用
  • J2ME 中提供了一个类似的类,它可以使您的应用程序更容易移植(但在这种情况下添加一个公共抽象层并不是很困难)
于 2009-01-04T01:19:12.293 回答
29

ExecutorService 更新更通用。计时器只是一个定期运行您为其安排的内容的线程。

ExecutorService 可能是一个线程池,甚至可以分布在集群中的其他系统中,并执行一次性批量执行等操作...

看看每个提供什么来决定。

于 2009-01-03T22:06:24.523 回答
17

以下是有关计时器使用的更多良好实践:

http://tech.puredanger.com/2008/09/22/timer-rules/

一般来说,我会使用 Timer 来处理快速而肮脏的东西,而使用 Executor 来获得更强大的使用。

于 2009-01-04T00:34:18.983 回答
9

来自ScheduledThreadPoolExecutor上的 Oracle 文档页面

一个ThreadPoolExecutor,可以额外安排命令在给定延迟后运行,或定期执行。当需要多个工作线程时,或者需要额外的灵活性或 ThreadPoolExecutor(此类扩展)的功能时,此类比Timer更可取。

ExecutorService/ThreadPoolExecutor或者ScheduledThreadPoolExecutor当您有多个工作线程时是明显的选择。

ExecutorService结束的优点Timer

  1. Timer不能利用可用的 CPU 内核,这与 使用ForkJoinPool之类ExecutorService的多任务的情况不同ExecutorService
  2. ExecutorService如果您需要在多个任务之间进行协调,则提供协作 API。假设您必须提交 N 个工作任务并等待所有任务完成。您可以使用invokeAll API 轻松实现它。如果您想通过多个Timer任务实现相同的目标,那就不简单了。
  3. ThreadPoolExecutor为管理线程生命周期提供了更好的 API。

    线程池解决了两个不同的问题:由于减少了每个任务的调用开销,它们通常在执行大量异步任务时提供改进的性能,并且它们提供了一种限制和管理资源的方法,包括执行一组线程时消耗的线程。任务。每个 ThreadPoolExecutor 还维护一些基本的统计信息,例如完成任务的数量

    几个优点:

    一种。您可以创建/管理/控制线程的生命周期并优化线程创建成本开销

    湾。您可以控制任务的处理(Work Stealing、ForkJoinPool、invokeAll)等。

    C。您可以监控线程的进度和健康状况

    d。提供更好的异常处理机制

于 2016-10-29T09:33:09.130 回答
5

我有时更喜欢 Timer 而不是 Executors.newSingleThreadScheduledExecutor() 的原因是,当我需要计时器在守护线程上执行时,我会得到更清晰的代码。

比较

private final ThreadFactory threadFactory = new ThreadFactory() {
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
};
private final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor(threadFactory); 

private final Timer timer = new Timer(true);

当我不需要 executorservice 的健壮性时,我会这样做。

于 2015-04-12T20:52:27.367 回答
2

我确实遇到了 Timer 问题,我用 ScheduledExecutorService替换它来修复它。

问题是计时器取决于系统时间,每次我更改它时,它都会影响应用程序的功能。所以我用ScheduledExecutorService替换了Timer ,现在它工作正常。

于 2021-03-10T04:06:10.583 回答