写完了基础篇,想了很久要不要去写进阶篇,去写JSP等等的使用方法,最后决定先不去写,因为自己并不是JAVA方面的大牛,目前也在边做边学,所以决定先将自己不懂的拿出来学并记下来。
Timer是Java自带的java.util.Timer类,通过调度一个java.util.TimerTask任务。这种方式可以让程序按照某一个频度执行。
1、Timer类的源码分析:
public class Timer { /** * The timer task queue. This data structure is shared with the timer * thread. The timer produces tasks, via its various schedule calls, * and the timer thread consumes, executing timer tasks as appropriate, * and removing them from the queue when they're obsolete. */ private TaskQueue queue = new TaskQueue(); /** * The timer thread. */ private TimerThread thread = new TimerThread(queue);
首先Timer类定义了两个私有变量TaskQueue和TimerThread。
TaskQueue:Timer类定义了一个定时器任务队列,一个TimerTasks的优先级队列。
class TaskQueue { /** * Priority queue represented as a balanced binary heap: the two children * of queue[n] are queue[2*n] and queue[2*n+1]. The priority queue is * ordered on the nextExecutionTime field: The TimerTask with the lowest * nextExecutionTime is in queue[1] (assuming the queue is nonempty). For * each node n in the heap, and each descendant of n, d, * n.nextExecutionTime <= d.nextExecutionTime. */ private TimerTask[] queue = new TimerTask[128];
TimerThread:Timer类的任务执行线程,从Thread类继承。以TaskQueue为参数。
在使用Timer类,首先new一个Timer对象,然后利用scheduleXXX函数执行任务,首先分析Timer对象构造过程:
public Timer() { this("Timer-" + serialNumber()); }
public Timer(boolean isDaemon) { this("Timer-" + serialNumber(), isDaemon); }<span style="white-space:pre"> </span>
public Timer(String name) { thread.setName(name); thread.start(); }
public Timer(String name, boolean isDaemon) { thread.setName(name); thread.setDaemon(isDaemon); thread.start(); }
可以看出,Timer在构造对象过程中,需要启动一个TimerThread线程,因此可以猜测,TimerThread线程和Timer对象共同维护一个TaskQueue,利用TaskQueue进行信息传递。
接下来看scheduleXXX函数,所有的scheduleXXX函数都需要调用sched方法,
private void sched(TimerTask task, long time, long period) { if (time < 0) throw new IllegalArgumentException("Illegal execution time."); synchronized(queue) { if (!thread.newTasksMayBeScheduled) throw new IllegalStateException("Timer already cancelled."); synchronized(task.lock) { if (task.state != TimerTask.VIRGIN) throw new IllegalStateException( "Task already scheduled or cancelled"); task.nextExecutionTime = time; task.period = period; task.state = TimerTask.SCHEDULED; } queue.add(task); if (queue.getMin() == task) queue.notify(); } }
这里首先介绍一下TimerTask类:
public abstract class TimerTask implements Runnable { /** * This object is used to control access to the TimerTask internals. */ final Object lock = new Object();
TimerTask类实现了Runnable接口,待执行的任务置于run()中。在构造定时任务的时候,从TimerTask继承并实现run方法。并创建任务传给scheduleXXX方法。
从sched方法中可以看出,sched方法中需要操作TaskQueue队列,而TimerThread线程启动之后同样使用这个队列,这就必须使用synchronized保证多线程安全使用。
2、scheduleXXX的使用:
Timer类的原理很简单,可以使用的函数不多,下面将全部列出。
(1)void java.util.Timer.schedule(TimerTask task, long delay):多长时间(毫秒)后执行任务
(2)void java.util.Timer.schedule(TimerTask task, Date time):设定某个时间执行任务
(3)void java.util.Timer.schedule(TimerTask task, long delay, long period):delay时间后开始执行任务,并每隔period时间调用任务一次。
(4)void java.util.Timer.schedule(TimerTask task, Date firstTime, long period):第一次在指定firstTime时间点执行任务,之后每隔period时间调用任务一次。
(5)void java.util.Timer.scheduleAtFixedRate(TimerTask task, long delay, long period):delay时间后开始执行任务,并每隔period时间调用任务一次。
(6)void java.util.Timer.scheduleAtFixedRate(TimerTask task, Date firstTime, long period):第一次在指定firstTime时间点执行任务,之后每隔period时间调用任务一次。
(7)void java.util.Timer.cancel():终止该Timer
(8)boolean java.util.TimerTask.cancel():终止该TimerTask
这些scheduleXXX方法中,除了(1)(2)外,其他都可以重复调用任务,主要的区别就是schedule和scheduleAtFixedRate的差别。
schedule()方法更注重保持间隔时间的稳定:保障每隔period时间可调用一次。
scheduleAtFixedRate()方法更注重保持执行频率的稳定:保障多次调用的频率趋近于period时间,如果某一次调用时间大于period,下一次就会尽量小于period,以保障频率接近于period
3、Timer类的使用示列
首先创建一个任务:
<pre name="code" class="java">import java.util.TimerTask; public class MyTask extends TimerTask{ private int id; public MyTask(int id){ this.id = id; } public void run(){ System.out.println("线程" + id + ":正在执行"); //System.gc(); } }
main函数代码:
import java.util.Date; import java.util.Timer; public class Test{ public static void main(String[] args){ Timer timer = new Timer(); timer.schedule(new MyTask(1), 5000);// 5秒后启动任务 MyTask secondTask = new MyTask(2); timer.schedule(secondTask, 1000, 3000); // 1秒后启动任务,以后每隔3秒执行一次线程 Date date = new Date(); timer.schedule(new MyTask(3), new Date(date.getTime() + 1000)); // 以date为参数,指定某个时间点执行线程 // timer.cancel(); // secondTask.cancel(); System.out.println("main thread 结束!"); } }
版权声明:本文为博主原创文章,未经博主允许不得转载。