Java Timer与ExecutorService之间的区别是什么?
Java中有两个常用的调度任务的工具类:Timer和ExecutorService。它们的出现是为了解决不同的需求。
Timer是一个用于调度任务的工具类,它使用单个线程来执行定时任务。它可以周期性地执行你预定的任务。Timer的优点是简单易用,但它的缺点是不适合处理需要长时间执行的任务,因为它只有一个线程,如果其中一个任务执行时间过长,会影响其他任务的执行。
ExecutorService是一个更加通用的调度任务的工具类。它可以是一个线程池,也可以分布在集群中的其他系统,并执行一次性批处理等操作。ExecutorService的优点是可以根据需要创建多个线程来执行任务,并且可以方便地管理任务的执行和取消。它的缺点是相对于Timer而言,使用起来稍微复杂一些。
为了决定使用哪个工具类,我们可以看一下它们各自的优势和适用场景。
如果我们只需要简单地在指定时间执行一些任务,并且不需要考虑任务执行时间过长的情况,那么可以选择使用Timer。它简单易用,可以满足基本的定时任务需求。
如果我们需要更灵活的任务调度,比如需要执行长时间的任务、一次性批处理任务或者需要管理任务的执行和取消,那么可以选择使用ExecutorService。它提供了更多的功能和灵活性,可以根据需求创建线程池,管理任务的执行。
Timer和ExecutorService是Java中常用的调度任务工具类。Timer适用于简单的定时任务,ExecutorService适用于更灵活的任务调度和管理。根据具体的需求,选择合适的工具类来实现任务调度。
Java中的定时器功能有两种实现方式:Timer和ExecutorService。根据《Java Concurrency in Practice》的解释,Timer存在一些问题,而ExecutorService则提供了更好的解决方案。
首先,Timer对系统时钟的变化非常敏感,而ScheduledThreadPoolExecutor则不会受到影响。这意味着当系统时钟发生变化时,Timer可能无法准确执行定时任务,而ScheduledThreadPoolExecutor则能够保持稳定。
其次,Timer只有一个执行线程,因此长时间运行的任务可能会延迟其他任务的执行。而ScheduledThreadPoolExecutor可以根据需要配置任意数量的线程。此外,通过提供ThreadFactory,可以对创建的线程进行完全控制。
另外,TimerTask中抛出的运行时异常会导致该线程被终止,从而使Timer无法继续执行定时任务。而ScheduledThreadPoolExecutor不仅会捕获运行时异常,还可以让你自定义处理异常的方式。通过重写ThreadPoolExecutor中的afterExecute方法,可以处理抛出异常的任务,而其他任务将继续执行。
因此,如果可以使用ScheduledThreadPoolExecutor代替Timer,就应该这样做。另外,虽然Java 1.4库中没有ScheduledThreadPoolExecutor,但可以使用Backport of JSR 166来实现类似的功能。
最后,ScheduledExecutorService对lambda表达式的支持也是一个优势。Timer无法使用lambda表达式,而ScheduledExecutorService可以接受lambda表达式作为参数,因为它接收的是"Runnable"而不是"TimerTask"。
根据《Java Concurrency in Practice》的建议,在Java中使用ScheduledThreadPoolExecutor是更好的选择。它提供了更稳定的定时器功能,并且具有更多的灵活性和错误处理能力。
Java Timer vs ExecutorService?
Java中的Timer和ExecutorService哪个更好用?
如果你可以使用它,那么很难想出不使用Java 5执行器框架的理由。调用:
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
将会给你一个具有类似功能的ScheduledExecutorService(即单线程),但其访问可能稍微更具可伸缩性(在底层使用并发结构,而不是像Timer类一样完全同步)。使用ScheduledExecutorService还有其他优点,比如:
- 如果需要,你可以自定义它(参见newScheduledThreadPoolExecutor()方法或ScheduledThreadPoolExecutor类)
- “一次性”的执行可以返回结果
我能想到坚持使用Timer的唯一理由是:
- 它在Java 5之前可用
- J2ME提供了一个类似的类,这可能使移植应用程序更容易(但在这种情况下添加一个通用的抽象层也不是太困难)
使用TimerTask的另一个原因可能是它提供了scheduledExecutionTime()方法,而在ScheduledExecutorService中似乎没有相对应的方法。
另一个注意事项:我在2017年写下这个评论,已经没有J2ME了,它已经消亡了。