关于Timer定时器

一:简单代码实现:


import java.util.Timer;
import java.util.TimerTask;

public class RunTimer {

	public static void main(String[] args) {
		Timer timer = new Timer();
		timer.schedule(new TestTamerTask(),0,1200);
		timer.scheduleAtFixedRate(new jiayou(), 0, 1200);
		
	}

}

class jiayou extends TimerTask{

	@Override
	public void run() {
		System.out.println("甲由由甲有假");
	}
	
}

二:理论知识:

1. TimerTimerTask

Timerjdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次。

TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务。

一些注意的问题

·        每一个Timer仅对应唯一一个线程。

·        Timer不保证任务执行的十分精确。

·        Timer类的线程安全的。

2.如何终止Timer线程

 默认情况下,创建的timer线程会一直执行,主要有下面四种方式来终止timer线程:

·        调用timercancle方法

·        timer线程设置成daemon线程,(new Timer(true)创建daemon   线程),在jvm里,如果所有用户线程结束,那么守护线程也会被终止,  不过这种方法一般不用。

·        当所有任务执行结束后,删除对应timer对象的引用,线程也会被终止。

·        调用System.exit方法终止程序

关于cancle方式终止线程

这种方式终止timer线程,jdk的实现比较巧妙,稍微说一下。

首先看cancle方法的源码:

public void cancel() {

       synchronized(queue) {

           thread.newTasksMayBeScheduled = false;

           queue.clear();

           queue.notify();  // In case queuewas already empty.

        }

 }

没有显式的线程stop方法,而是调用了queueclear方法和queuenotify方法,clear是个自定义方法,notifyObjec自带的方法,很明显是去唤醒wait方法的。

再看clear方法:

void clear() {

       // Null out task references to prevent memory leak

       for (int i=1; i<=size; i++)

           queue[i] = null;

 

       size = 0;

    }

clear方法很简单,就是去清空queuequeue是一个TimerTask的数组,然后把queuesize重置成0,变成empty.还是没有看到显式的停止线程方法,回到最开始new Timer的时候,看看new Timer代码:

public Timer() {

       this("Timer-" + serialNumber());

    }

  public Timer(String name) {

        thread.setName(name);

        thread.start();

}

看看这个内部变量thread:

 private TimerThread thread = new TimerThread(queue);

不是原生的Thread,是自定义的类TimerThread.这个类实现了Thread类,重写了run方法,如下:

public void run() {

        try {

            mainLoop();

        } finally {

            // Someonekilled this Thread, behave as if Timer cancelled

           synchronized(queue) {

               newTasksMayBeScheduled = false;

               queue.clear();  // Eliminateobsolete references

            }

        }

}

最后是这个mainLoop方法,这方法比较长,截取开头一段:

private void mainLoop() {

        while (true) {

            try {

               TimerTask task;

                booleantaskFired;

               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;

 

可以看到wait方法,之前的notify就是通知到这个wait,然后clear方法在notify之前做了清空数组的操作,所以会break,线程执行结束,退出。


3.schedule和scheduleAtFixedRate

(1)2个参数的schedule在制定任务计划时, 如果指定的计划执行时间 scheduledExecutionTime<=systemCurrentTime,则task会被立即执行。 scheduledExecutionTime不会因为某一个task的过度执行而改变。
(2)3个参数的schedule在制定反复执行一个task的计划时,每一次执行这个task的计划执行时间随着前一次的实际执行时间而变,也就是scheduledExecutionTime(第n+1次)=realExecutionTime(第n次)+periodTime。也就是说如果第n 次执行task时,由于某种原因这次执行时间过长,执行完后的 systemCurrentTime>=scheduledExecutionTime(第n+1次),则此时不做时隔等待,立即执行第n+1次 task,而接下来的第n+2次task的scheduledExecutionTime(第n+2次)就随着变成了realExecutionTime(第n+1次)+periodTime。说白了,这个方法更注重保持间隔时间的稳定。
(3)3个参数的scheduleAtFixedRate 在制定反复执行一个task的计划时,每一次执行这个task的计划执行时间在最初就被定下来了,也就是 scheduledExecutionTime(n)=firstExecuteTime+n*periodTime;如果第n次执行task时,由于某种原因这次执行时间过长,执行完后的systemCurrentTime>=scheduledExecutionTime(n+1),则此时不做period间隔等待,立即执行第n+1task,而接下来的第n+2次的taskscheduledExecutionTime(n+2 )依然还是firstExecuteTime+n+2)*periodTime这在第一次执行task就定下来了。说白了,这个方法更注重保持执行频率的稳定。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值