Java Timer与ExecutorService?


263

我有使用计划任务的代码java.util.Timer。我环顾四周,发现ExecutorService可以做到这一点。因此,这里有一个问题,您是否使用过TimerExecutorService安排了任务,一次使用比另一次使用有什么好处?

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


1
而且,如果您需要更全面的功能,请查看石英。它为您提供了更多的作业控制,包括cron之类的调度,可感知群集的调度,对作业的个性化控制(诸如一次运行,相关性等概念)。--Tim
Tim

Answers:


313

根据实践中的Java并发性

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

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

还有一件事...尽管ScheduledThreadExecutorJava 1.4库中没有该功能,但是有一个将JSR 166(java.util.concurrent)反向移植到Java 1.2、1.3、1.4ScheduledThreadExecutor类。


63

如果您可以使用它,那么很难考虑使用Java 5执行程序框架的原因。致电:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

会为您提供ScheduledExecutorService与相似的功能Timer(即它将是单线程的),但其访问权限可能会稍微扩展(在幕后,它使用并发结构而不是像使用Timer类那样进行完全同步)。使用a ScheduledExecutorService还可以为您带来以下优势:

  • 您可以根据需要对其进行自定义(请参见newScheduledThreadPoolExecutor()ScheduledThreadPoolExecutor类)
  • 一次性执行可以返回结果

Timer我能想到的唯一坚持的理由是:

  • Java 5之前可用
  • J2ME中提供了一个类似的类,它可以使您的应用程序的移植更加容易(但是在这种情况下,添加通用的抽象层并不是很困难)

1
使用的另一个原因TimerTask可能是scheduledExecutionTime()方法的可用性似乎在中没有任何等效方法ScheduledExecutorService
罗希特·阿加瓦尔

3
另一个注意事项:我在2k17中写此评论,没有更多的J2ME。它已经死了。
msangel '17

1
Java Timer类很糟糕。
JohnyTex'17 October

26

ExecutorService较新且更通用。计时器只是一个线程,它定期运行您为其安排的工作。

ExecutorService可以是线程池,甚至可以分布在群集中的其他系统上,并执行一次性批处理等操作。

只需看看每个决定提供什么。



8

ScheduledThreadPoolExecutor上的Oracle文档页面

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

ExecutorService/ThreadPoolExecutor或者ScheduledThreadPoolExecutor当您有多个工作线程时,这是显而易见的选择。

ExecutorService超过的优点Timer

  1. Timer不能利用可用的CPU内核, ExecutorService尤其是在使用ExecutorService诸如ForkJoinPool之类的多种任务的情况下
  2. ExecutorService如果需要在多个任务之间进行协调,则提供协作式API。假设您必须提交N个工作者任务,然后等待所有任务完成。您可以使用invokeAll API 轻松实现它。如果您想通过多个Timer任务来实现相同的目标,那将不容易。
  3. ThreadPoolExecutor提供了更好的API,用于管理线程生命周期。

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

    几个优点:

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

    b。您可以控制任务的处理(工作窃取,ForkJoinPool,invokeAll)等。

    C。您可以监视线程的进度和运行状况

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


5

我之所以有时偏爱计时器而不是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的鲁棒性时,我会这样做。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.