Java中还封装提供了另一种非常有用的线程使用方法,这就是定时任务:Java在util包中提供了Timer类和TimerTask类。Timer类代表定时器,TimerTask是定时器任务。
先讲一下比较简单的TimerTask类,这是一个抽象类,实现了Runnable接口,但并没有实现run方法。你的定时器任务就是继承TimerTask类,实现run方法即可。
Timer类,定时器,其中定义了两个比较重要的内部类,TimerThread类和TimerQueue类。并且Timer类中有一个TimerQueue类型的成员变量queue和TimerThread类型的成员变量thread。在创建thread实例时,会将queue对象引用传入到thread中,Timer 类中代码如下:
TimerQueue queue = new TimerQueue();
TimerThread thread = new TimerThread(queue);
在Timer的构造函数中,就会执行thread.start()方法,即启动其中的定时器线程。
TimerQueue是一个TimerTask容器,其中就是一个TimerTask 数组。TimerThread 类继承Thread类,就是一个线程,其中重写了Thread的run方法,为一个while(true)循环,即遍历queue对象,如果得到一个TimerTask实例,就调用执行其run方法。
从上面的描述中可以看到,Timer实例和TimerThread实例会把持同一个TimerQueue对象。这就是一个生产者、消费者模型,Timer实例往TimerQueue对象中添加TimerTask实例,TimerThread实例不断去消费同一个TimerQueue对象中的TimerTask实例。这里还涉及到多线程的并发互斥控制,这个后续会提到。
综上,使用定时器是个十分简单的过程:
Timer timer = new Timer(); // 此时定时器线程TimerThread已经开始运行
TimerTask task = new MyTimerTask(); // 创建自己的定时器任务
timer.schedule(task, 0);// 往timer中的TimerQueue这个数据结构中添加一个定时任务,定时器线程会去执行
这样定时器就可以运行了。此外schedule方法还有很多重载形式。
注意:TimerTask中有一个标示,就是代表这个TimerTask是否已经被定时器线程执行过,一个被执行过的TimerTask
不能再重新被schedule到定时器中去执行,否则会报java.lang.IllegalStateException 异常。