当前位置:编程学习 > JAVA >>

深入浅出Java Concurrency : 线程池 part 5 周期性任务调度

周期性任务调度前世

在JDK 5.0之前,java.util.Timer/TimerTask是唯一的内置任务调度方法,而且在很长一段时间里很热衷于使用这

种方式进行周期性任务调度。

首先研究下Timer/TimerTask的特性(至于javax.swing.Timer就不再研究了)。

public void schedule(TimerTask task, long delay, long period) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, System.currentTimeMillis()+delay, -period);
}
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
    if (delay < 0)
        throw new IllegalArgumentException("Negative delay.");
    if (period <= 0)
        throw new IllegalArgumentException("Non-positive period.");
    sched(task, System.currentTimeMillis()+delay, period);
}
 

public class Timer {

    private TaskQueue queue = new TaskQueue();
    /**
     * The timer thread.
     */
    private TimerThread thread = new TimerThread(queue);
 
 

java.util.TimerThread.mainLoop()

private void mainLoop() {
    while (true) {
        try {
            TimerTask task;
            boolean taskFired;
            synchronized(queue) {
                // Wait for queue to become non-empty
                while (queue.isEmpty() && newTasksMayBeScheduled)
                    queue.wait();
                if (queue.isEmpty())
                    break; // Queue is empty and will forever remain; die
。。。。。。
                
                if (!taskFired) // Task hasnt yet fired; wait
                    queue.wait(executionTime - currentTime);
            }
            if (taskFired)  // Task fired; run it, holding no locks
                task.run();
        } catch(InterruptedException e) {
        }
    }
}
 

上面三段代码反映了Timer/TimerTask的以下特性:

Timer对任务的调度是基于绝对时间的。
所有的TimerTask只有一个线程TimerThread来执行,因此同一时刻只有一个TimerTask在执行。
任何一个TimerTask的执行异常都会导致Timer终止所有任务。
由于基于绝对时间并且是单线程执行,因此在多个任务调度时,长时间执行的任务被执行后有可能导致短

时间任务快速在短时间内被执行多次或者干脆丢弃多个任务。
由于Timer/TimerTask有这些特点(缺陷),因此这就导致了需要一个更加完善的任务调度框架来解决这些

问题。

周期性任务调度今生

java.util.concurrent.ScheduledExecutorService的出现正好弥补了Timer/TimerTask的缺陷。

public interface ScheduledExecutorService extends ExecutorService {
    public ScheduledFuture<?> schedule(Runnable command,
                       long delay, TimeUnit unit);
 
    public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                       long delay, TimeUnit unit);
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                          long initialDelay,
                          long period,
                          TimeUnit unit);
 
    public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                             long initialDelay,
                             long delay,
                             TimeUnit unit);
}
 

首先ScheduledExecutorService基于ExecutorService,是一个完整的线程池调度。另外在提供线程池的基础上增加

了四个调度任务的API。

schedule(Runnable command,long delay, TimeUnit unit):在指定的延迟时间一次性启动任务(Runnable),没有

返回值。
schedule(Callable<V> callable, long delay, TimeUnit unit):在指定的延迟时间一次性启动任务(Callable),携带

一个结果。
scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit):建并执行一个在给定初始

延迟后首次启用的定期操作,后续操作具有给定的周期;也就是将在 initialDelay 后开始执行,然后在 initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推。如果任务的任何一个执行

遇到异常,则后续执行都会被取消。否则,只能通过执行程序的取消或终止方法来终止该任务。如果此任务的

任何一个执行要花费比其周期更长的时间,则将推迟后续执行,但不会同时执行。
scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit):创建并执行一个在给定

初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次执行开始之间都存在给定的延迟。如果

任务的任一执行遇到异常,就会取消后续执行。否则,只能通过执行程序的取消或终止方法来终止该任务。
上述API解决了以下几个问题:

ScheduledExecutorService任务调度是基于相对时间,不管是一次性任务还是周期性任务都是相对于任务加入

线程池(任务队列)的时间偏移。
基于线程池的ScheduledExecutorService允许多个线程同时执行任务,这在添加多种不同调度类型的任务是非常

有用的。
同样基于线程池的ScheduledExecutorService在其中一个任务发生异常时会退出执行线程,但同时会有新的线程

补充进来进行执行。
ScheduledExecutorService可以做到不丢失任务。
下面的例子演示了一个任务周期性调度的例子。

package xylz.study.concurrency.executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorServiceDemo {
    public static void main(String[

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,