我有一段代码,使用java.util.Timer
来安排任务。我看到ExecutorService
也可以完成相同的任务。所以我的问题是,你是否使用过Timer
和ExecutorService
来安排任务,其中一个的好处是什么?
另外,我想知道是否有人使用Timer
类并遇到了ExecutorService
解决的问题。
我有一段代码,使用java.util.Timer
来安排任务。我看到ExecutorService
也可以完成相同的任务。所以我的问题是,你是否使用过Timer
和ExecutorService
来安排任务,其中一个的好处是什么?
另外,我想知道是否有人使用Timer
类并遇到了ExecutorService
解决的问题。
Timer
对系统时钟的更改敏感,ScheduledThreadPoolExecutor
则不会。Timer
只有一个执行线程,因此长时间运行的任务可能会延迟其他任务。 ScheduledThreadPoolExecutor
可以配置任意数量的线程。此外,如果需要的话(通过提供 ThreadFactory
),您可以完全控制创建的线程。TimerTask
中抛出的运行时异常会终止该线程,从而使 Timer
失效:-(...即预定的任务将不再运行。 ScheduledThreadExecutor
不仅捕获运行时异常,而且如果需要,它还可以让您处理这些异常(通过覆盖来自 ThreadPoolExecutor
的 afterExecute
方法)。抛出异常的任务将被取消,但其他任务将继续运行。如果可以使用 ScheduledThreadExecutor
而不是 Timer
,请这样做。
还有一件事...虽然 Java 1.4 库中没有 ScheduledThreadExecutor
,但是有一个 JSR 166 的后备方案(java.util.concurrent
)可用于 Java 1.2、1.3、1.4,其中包含 ScheduledThreadExecutor
类。
如果您可以使用,很难想到不使用Java 5执行器框架的理由。调用:
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
使用 ScheduledExecutorService
将为您提供类似于 Timer
的功能(即它将是单线程的),但其访问可能会稍微更加可扩展(在内部,它使用并发结构而不是与 Timer
类一样的完全同步)。 使用 ScheduledExecutorService
还具有以下优点:
newScheduledThreadPoolExecutor()
或 ScheduledThreadPoolExecutor
类)我能想到坚持使用 Timer
的唯一原因是:
TimerTask
的另一个原因可能是它提供了scheduledExecutionTime()
方法,而在ScheduledExecutorService
中似乎没有相应的方法。 - Rohit AgarwalExecutorService是较新且更通用的。定时器只是定期运行您为其安排的内容的线程。
ExecutorService可以是线程池,甚至可以分布在集群中的其他系统上,执行诸如一次性批处理等操作...
只需查看每个提供的功能即可决定使用哪一个。
以下是关于ScheduledThreadPoolExecutor的Oracle文档页面:
ScheduledThreadPoolExecutor 是一个线程池执行器,可以在给定延迟后调度命令运行,或定期执行。当需要多个工作线程时,或需要 ThreadPoolExecutor(该类扩展了此类)的额外灵活性或功能时,此类比 Timer 更可取。
当您有多个工作线程时,ExecutorService/ThreadPoolExecutor
或 ScheduledThreadPoolExecutor
是明显的选择。
ExecutorService
相对于 Timer
的优点:
Timer
无法利用可用的CPU核心,不像使用ForkJoinPool等ExecutorService
的多个任务可以。ExecutorService
提供了协同API,如果您需要协调多个任务之间的操作。假设您必须提交N个工作任务并等待它们全部完成,您可以轻松使用invokeAll API实现。如果要使用多个Timer
任务实现相同的操作,那将不会简单。线程池解决了两个不同的问题:由于减少了每个任务调用开销,因此在执行大量异步任务时通常提供了改进的性能,并且它们提供了一种控制和管理资源(包括线程)的手段,这些资源在执行任务集合时消耗。每个ThreadPoolExecutor还维护一些基本统计信息,例如已完成的任务数
优点如下:
a. 您可以创建/管理/控制线程的生命周期和优化线程创建成本开销
b. 您可以控制任务的处理方式(工作窃取、ForkJoinPool、invokeAll)等。
c. 您可以监视线程的进度和健康状况
d. 提供更好的异常处理机制
我有时候更喜欢使用 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);
当我不需要执行器服务的强大功能时,我会这样做。
我曾经遇到一个计时器的问题,为了解决它,我用ScheduledExecutorService进行了替换。
问题在于计时器依赖于系统时间,每次改变时间都会影响应用程序的运行。所以我用ScheduledExecutorService替换了计时器,现在它正常工作。