当前位置: 首页 > 工具软件 > Timer > 使用案例 >

Timer定时器用法详解

邓子濯
2023-12-01

先看API和结论:

/**
    timer总结:
    Timer timer = new Timer();    //其中会调用this("Timer-" + serialNumber());, 即它以Timer+序列号为该定时器的名字
    Timer timer = new Timer(String name);    //以name作为该定时器的名字
    Timer timer = new Timer(boolean isDeamon);    //是否将此定时器作为守护线程执行
    Timer timer = new Timer(name, isDeamon);    //定时器名字, 是否为守护线程
    
    注意:
    默认无参构造器将会使该线程作为非守护线程, 即使主线程已经停止并销毁, 只要该线程还存在, 则程序不会停止
    即下面的所有执行的任务, 无论是否是定时还是非定时, 只要主线程一旦结束, 那么该定时器立即同主线程一起销毁
    
    以下所有的task都是TimerTask的子类
    所有time都是Date类型的日期
    所有delay和period都是long类型的延迟时间, 单位为毫秒
    timer.schedule(task, time);                    在time时间执行task任务1次
    timer.schedule(task, delay);                在延迟delay毫秒后执行task任务1次
    timer.schedule(task, firstTime, period);    在firsttime时间执行task1次,之后定期period毫秒时间执行task,    时间如果为过去时间, 不会执行过去没有执行的任务, 但是会马上执行
    timer.schedule(task, delay, period);        在延迟delay后执行task1次,之后定期period毫秒时间执行task,     时间如果为过去时间, 不会执行过去没有执行的任务, 但是会马上执行
    
    timer.scheduleAtFixedRate(task, firstTime, period);        在firstTime时间执行task一次, 以后每隔period毫秒执行1次, 时间如果为过去时间, 会执行过去没有执行的任务, 但是会马上执行
    timer.scheduleAtFixedRate(task, delay, period);            在delay毫秒后执行task一次, 以后每隔period毫秒执行1次, 时间如果为过去时间, 会执行过去没有执行的任务, 但是会马上执行
    
    区别:test4();
    timer.schedule(task, firstTime, period);
    timer.scheduleAtFixedRate(task, firstTime, period);
    从test4运行结果可以看到, 如果开始时间在过去, 则
        schedule会表现出只从当前时间开始,
        scheduleAtFixedRate会把之前没有来得及执行的任务全都执行, 感觉像之前一直有在执行一样
        
    区别: test5()
    timer.schedule(task, time);
    timer.schedule(task, delay);
    其中, 如果time时间为过去时间, 则该任务会马上执行, 如果为将来时间, 则会等待时间到来再执行
    如果传入的是delay, 则delay不可以为负数, 负数报错, 正数代表未来的delay毫秒以后执行
    
    
    小结:
        时间如果为过去时间, 则所有scheduke和scheduleAtFixedRate都会立即执行
        并且scheduke不会执行过去的任务, 而scheduleAtFixedRate则会把过去的任务全都执行, 即按照固定时间执行一样
        isDeamon决定是否该Timer以守护线程存在

    timer.purge();
    先看英文描述:
    Removes all cancelled tasks from this timer's task queue. Calling this method has no effect on the behavior of the timer, but eliminates the references to the cancelled tasks from the queue. If there are no external references to these tasks, they become eligible for garbage collection. 
    Most programs will have no need to call this method. It is designed for use by the rare application that cancels a large number of tasks. Calling this method trades time for space: the runtime of the method may be proportional to n + c log n, where n is the number of tasks in the queue and c is the number of cancelled tasks. 
    Note that it is permissible to call this method from within a a task scheduled on this timer.
    Returns:
    the number of tasks removed from the queue.
    Since:
    1.5
    即purge();对实际的timer的任务执行不会有影响, 它仅仅只会移除所有被取消的任务队列的引用以方便垃圾回收, 通常不用调用此方法, 只有任务数非常多(n + c log n)的时候, 可以调用此方法以时间换取空间.
    
    timer.cancel();
    Terminates this timer, discarding any currently scheduled tasks. Does not interfere with a currently executing task (if it exists). Once a timer has been terminated, its execution thread terminates gracefully, and no more tasks may be scheduled on it. 
    Note that calling this method from within the run method of a timer task that was invoked by this timer absolutely guarantees that the ongoing task execution is the last task execution that will ever be performed by this timer. 
    This method may be called repeatedly; the second and subsequent calls have no effect.
    即cancel();停止该timer, 并且丢弃所有绑定的任务, 但不干预当前正在执行的任务。一旦timer停止了, 那么其执行线程将会优雅终止, 并且该timer不可以再绑定task任务了
 */

再看测试代码:

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
/**
	timer总结:
	Timer timer = new Timer();	//其中会调用this("Timer-" + serialNumber());, 即它以Timer+序列号为该定时器的名字
	Timer timer = new Timer(String name);	//以name作为该定时器的名字
	Timer timer = new Timer(boolean isDeamon);	//是否将此定时器作为守护线程执行
	Timer timer = new Timer(name, isDeamon);	//定时器名字, 是否为守护线程
	
	注意:
	默认无参构造器将会使该线程作为非守护线程, 即使主线程已经停止并销毁, 只要该线程还存在, 则程序不会停止
	即下面的所有执行的任务, 无论是否是定时还是非定时, 只要主线程一旦结束, 那么该定时器立即同主线程一起销毁
	
	以下所有的task都是TimerTask的子类
	所有time都是Date类型的日期
	所有delay和period都是long类型的延迟时间, 单位为毫秒
	timer.schedule(task, time);					在time时间执行task任务1次
	timer.schedule(task, delay);				在延迟delay毫秒后执行task任务1次
	timer.schedule(task, firstTime, period);	在firsttime时间执行task1次,之后定期period毫秒时间执行task,	时间如果为过去时间, 不会执行过去没有执行的任务, 但是会马上执行
	timer.schedule(task, delay, period);		在延迟delay后执行task1次,之后定期period毫秒时间执行task, 	时间如果为过去时间, 不会执行过去没有执行的任务, 但是会马上执行
	
	timer.scheduleAtFixedRate(task, firstTime, period);		在firstTime时间执行task一次, 以后每隔period毫秒执行1次, 时间如果为过去时间, 会执行过去没有执行的任务, 但是会马上执行
	timer.scheduleAtFixedRate(task, delay, period);			在delay毫秒后执行task一次, 以后每隔period毫秒执行1次, 时间如果为过去时间, 会执行过去没有执行的任务, 但是会马上执行
	
	区别:test4();
	timer.schedule(task, firstTime, period);
	timer.scheduleAtFixedRate(task, firstTime, period);
	从test4运行结果可以看到, 如果开始时间在过去, 则
		schedule会表现出只从当前时间开始,
		scheduleAtFixedRate会把之前没有来得及执行的任务全都执行, 感觉像之前一直有在执行一样
		
	区别: test5()
	timer.schedule(task, time);
	timer.schedule(task, delay);
	其中, 如果time时间为过去时间, 则该任务会马上执行, 如果为将来时间, 则会等待时间到来再执行
	如果传入的是delay, 则delay不可以为负数, 负数报错, 正数代表未来的delay毫秒以后执行
	
	
	小结:
		时间如果为过去时间, 则所有scheduke和scheduleAtFixedRate都会立即执行
		并且scheduke不会执行过去的任务, 而scheduleAtFixedRate则会把过去的任务全都执行, 即按照固定时间执行一样
		isDeamon决定是否该Timer以守护线程存在

	timer.purge();
	先看英文描述:
	Removes all cancelled tasks from this timer's task queue. Calling this method has no effect on the behavior of the timer, but eliminates the references to the cancelled tasks from the queue. If there are no external references to these tasks, they become eligible for garbage collection. 
	Most programs will have no need to call this method. It is designed for use by the rare application that cancels a large number of tasks. Calling this method trades time for space: the runtime of the method may be proportional to n + c log n, where n is the number of tasks in the queue and c is the number of cancelled tasks. 
	Note that it is permissible to call this method from within a a task scheduled on this timer.
	Returns:
	the number of tasks removed from the queue.
	Since:
	1.5
	即purge();对实际的timer的任务执行不会有影响, 它仅仅只会移除所有被取消的任务队列的引用以方便垃圾回收, 通常不用调用此方法, 只有任务数非常多(n + c log n)的时候, 可以调用此方法以时间换取空间.
	
	timer.cancel();
	Terminates this timer, discarding any currently scheduled tasks. Does not interfere with a currently executing task (if it exists). Once a timer has been terminated, its execution thread terminates gracefully, and no more tasks may be scheduled on it. 
	Note that calling this method from within the run method of a timer task that was invoked by this timer absolutely guarantees that the ongoing task execution is the last task execution that will ever be performed by this timer. 
	This method may be called repeatedly; the second and subsequent calls have no effect.
	即cancel();停止该timer, 并且丢弃所有绑定的任务, 但不干预当前正在执行的任务。一旦timer停止了, 那么其执行线程将会优雅终止, 并且该timer不可以再绑定task任务了
	
	
 */
public class TimerTest {

	public static void main(String[] args) {
//		test1();		//测试schedule功能
//		test2();		//测试所有scheduleAtFixedRate功能
//		test3();		//测试isDeamon对Timer的影响
//		test4();		//测试AtFixedRateSchedule和schedule区别
//		test5();		//测试schedule在过去时间的表现, 如果firstTime是过去时间, 则立即执行, 如果是未来时间, 则会等待时间到之后执行, 如果是传入延迟时间, 则延迟时间不能为负数, 否则报错
//		test6();		
		test7();
	}
	
	public static void test1()
	{
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("执行了1次");
			}
		}, 1000);
		
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("执行了2次");
			}
		}, getDelayTime(2));
		
		//第3和第4个task的执行顺序是不确定的,因为时间片的切换导致的微小差别
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("执行了3次");
			}
		}, getDelayTime(3), 1000);	//3, -3
		
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.err.println("执行了4次");
			}
		}, 1000, 1000);
	}
	public static void test2()
	{
		Timer timer = new Timer();
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				System.out.println("AtFixedRate1");
			}
		}, getDelayTime(1), 1000);
		
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				System.out.println("AtFixedRate2");
			}
		}, 2000, 1000);
	}
	
	public static void test3()
	{
		Timer timer = new Timer("isDeamon", true);
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("isDeamon");
				try {
					Thread.sleep(10000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}, getDelayTime(2), 2000);
	}
	
	public static void test4()
	{
		Timer timer = new Timer("AtFixedRate", false);
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("schedule");
			}
		}, getDelayTime(-5), 2000);
		
		timer.scheduleAtFixedRate(new TimerTask() {
			@Override
			public void run() {
				System.out.println("scheduleAtFixedRate");
			}
		}, getDelayTime(-5), 2000);
	}
	
	public static void test5()
	{
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("测试时间为过去时间和将来时间对schedule的影响");
			}
		}, getDelayTime(-5));	//立即执行
	}
	
	public static void test6()
	{
		//purge: 清洗, 净化
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("测试purge1");
			}
		}, getDelayTime(1), 1000);
		System.out.println("purge: "+timer.purge());
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("测试purge2");
			}
		}, getDelayTime(1), 1000);
	}
	
	public static void test7()
	{
		//将7和6对比看
		Timer timer = new Timer();
		class MyTimerTask extends TimerTask{
			@Override
			public void run() {
				System.out.println("测试purge1");
				this.cancel();
			}
		}
		for(int i = 0; i<100; i++)
		{
			MyTimerTask mt = new MyTimerTask();
			timer.schedule(mt, getDelayTime(1), 1000);
			mt.cancel();
		}
//		timer.cancel();
		System.out.println("此时可以移除取消的任务数为100个: "+timer.purge());
		/*timer.schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("我现在还可以执行~~");
			}
		}, getDelayTime(2));*/
		
		
		for(int i = 0; i<100; i++)
		{
			MyTimerTask mt = new MyTimerTask();
			mt.cancel();
			timer.schedule(mt, getDelayTime(1), 1000);
		}
		System.out.println("此时可以移除取消的任务数为100个: "+timer.purge());
		///
	}
	
	//给定一个时间,返回给定多久以后的Date
	public static Date getDelayTime(int howlong)
	{
		Calendar cld = Calendar.getInstance();
		cld.set(Calendar.SECOND, howlong+cld.get(Calendar.SECOND));
		return cld.getTime();
	}
}

其中难点只有这个purge的使用,下面这篇文章详细解释了purge在queue队列非常大时如何避免内存泄漏的

Java定时任务Timer调度器【三】 注意事项(任务精确性与内存泄漏)

这里有个问题待考虑:为什么purge()返回值一直是0,我已经将TimerTask任务取消,但是返回的purge()还是0.这点很奇怪。

其他类似文章:

定时器Timer

 类似资料: