我有使用java.util.Timer调度任务的代码。我环顾四周,发现ExecutorService也能做到这一点。这里的问题是,你是否使用Timer和ExecutorService来调度任务,使用它们有什么好处?

还想检查是否有人使用了Timer类,并遇到了ExecutorService为他们解决的任何问题。


ExecutorService更新且更通用。计时器只是一个线程,它周期性地运行你为它安排的事情。

ExecutorService可以是一个线程池,甚至可以分布在集群中的其他系统中,执行诸如一次性批处理执行之类的事情……

只要看看每家公司提供的服务就能决定。


根据Java并发实践:

Timer can be sensitive to changes in the system clock, ScheduledThreadPoolExecutor isn't. Timer has only one execution thread, so long-running task can delay other tasks. ScheduledThreadPoolExecutor can be configured with any number of threads. Furthermore, you have full control over created threads, if you want (by providing ThreadFactory). Runtime exceptions thrown in TimerTask kill that one thread, thus making Timer dead :-( ... i.e. scheduled tasks will not run anymore. ScheduledThreadExecutor not only catches runtime exceptions, but it lets you handle them if you want (by overriding afterExecute method from ThreadPoolExecutor). Task which threw exception will be canceled, but other tasks will continue to run.

如果你可以使用ScheduledThreadExecutor而不是Timer,那么就这样做。

还有一件事……虽然ScheduledThreadExecutor在Java 1.4库中不可用,但JSR 166 (Java .util.concurrent)有一个到Java 1.2、1.3、1.4的Backport,其中有ScheduledThreadExecutor类。


如果您可以使用Java 5执行程序框架,那么就很难想出不使用它的理由。调用:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

将为您提供一个ScheduledExecutorService,具有与Timer类似的功能(即它将是单线程的),但其访问可能更具伸缩性(在底层,它使用并发结构,而不是像Timer类那样完全同步)。使用ScheduledExecutorService还可以为您提供以下优势:

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

我能想到的坚持使用Timer的唯一原因是:

它在Java 5之前可用 J2ME中提供了一个类似的类,它可以使移植应用程序更容易(但在本例中添加一个公共抽象层并不难)


我有时更喜欢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的健壮性时,我就这样做。


从Oracle文档页ScheduledThreadPoolExecutor

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

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

ExecutorService优于Timer的优点

Timer can't take advantage of available CPU cores unlike ExecutorService especially with multiple tasks using flavours of ExecutorService like ForkJoinPool ExecutorService provides collaborative API if you need coordination between multiple tasks. Assume that you have to submit N number of worker tasks and wait for completion of all of them. You can easily achieve it with invokeAll API. If you want to achieve the same with multiple Timer tasks, it would be not simple. ThreadPoolExecutor provides better API for management of Thread life cycle. Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks. Each ThreadPoolExecutor also maintains some basic statistics, such as the number of completed tasks Few advantages: a. You can create/manage/control life cycle of Threads & optimize thread creation cost overheads b. You can control processing of tasks ( Work Stealing, ForkJoinPool, invokeAll) etc. c. You can monitor the progress and health of threads d. Provides better exception handling mechanism


我确实有定时器的问题,我用ScheduledExecutorService替换了它来修复它。

问题是定时器取决于系统时间,每次我改变它,它会影响应用程序的功能。所以我用ScheduledExecutorService替换了Timer,现在它工作得很好。