Timer的schedule和scheduleAtFixedRate方法的区别解析

   在Java中,Timer类主要用于定时性、周期性任务 的触发,这个类中有两个方法比较难理解,那就是schedule和scheduleAtFixedRate方法,在这里就用实例分析一下

   (1)在方法不延迟的情况下,即间隔时间大于任务执行时间时:

     

package test;

import java.util.Calendar;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

public class Test1 {
	static class MyTask extends TimerTask{
		public void run(){
				try {
					System.out.println("begin timer="+System.currentTimeMillis());
					Thread.sleep(1000);
					System.out.println(" end timer="+System.currentTimeMillis());
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
		}
	}
	public static void main(String[] args) {
		MyTask task = new MyTask();
		Calendar caldef = Calendar.getInstance();
		Date runDate = caldef.getTime();
	    Timer timer = new Timer();
	    timer.schedule(task, runDate,3000);
	}
}

 schedule方法输出 结果:

  begin timer=1490009857383

  end timer=1490009858383

begin timer=1490009860383

  end timer=1490009861383

begin timer=1490009863383

  end timer=1490009864383

scheduleAtFixedRate方法输出结果:

begin timer=1490009967115

  end timer=1490009968116

begin timer=1490009970096

  end timer=1490009971096

begin timer=1490009973096

  end timer=1490009974096

可以看出因为间隔3秒大于任务执行时间1秒,2个方法都是以开始时间每隔3秒固定执行一次,下一次开始时间都是以上一次开始时间加上固定间隔执行

(2)当延迟的情况下,即任务执行时间大于间隔时

 
public class Test1 {
static class MyTask extends TimerTask{
public void run(){
try {
System.out.println("begin timer="+System.currentTimeMillis());
Thread.sleep(5000);
System.out.println(" end timer="+System.currentTimeMillis());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
MyTask task = new MyTask();
Calendar caldef = Calendar.getInstance();
Date runDate = caldef.getTime();
Timer timer = new Timer();
timer.schedule(task, runDate,3000);
}
}

  schedule方法输出:

  begin timer=1490010207645

  end timer=1490010212646

begin timer=1490010212646

  end timer=1490010217646

begin timer=1490010217646

  end timer=1490010222646

scheduleAtFixedRate方法输出结果:

begin timer=1490010370413

  end timer=1490010375413

begin timer=1490010375413

  end timer=1490010380413

begin timer=1490010380413

  end timer=1490010385414

 可以看出因为任务时间5秒大于时间间隔3秒时,2个方法都是每隔5秒固定执行一次,下一次开始时间都是以上一次结束时间为准

(3)验证2种方法的追赶性,即任务计划执行时间早于任务执行时间

 
static class MyTask extends TimerTask{
public void run(){
System.out.println("begin timer="+new Date());
System.out.println(" end timer="+new Date());
}
}
public static void main(String[] args) {
MyTask task = new MyTask();
System.out.println("现在执行时间: "+new Date());
Calendar caldef = Calendar.getInstance();
caldef.set(Calendar.SECOND, caldef.get(Calendar.SECOND)-20);
Date runDate = caldef.getTime();
System.out.println("计划执行时间: "+runDate);
Timer timer = new Timer();
timer.schedule(task, runDate,2000);
}

 

  schedule方法输出:

  现在执行时间: Mon Mar 20 19:53:56 CST 2017

计划执行时间: Mon Mar 20 19:53:36 CST 2017

begin timer=Mon Mar 20 19:53:56 CST 2017

  end timer=Mon Mar 20 19:53:56 CST 2017

begin timer=Mon Mar 20 19:53:58 CST 2017

  end timer=Mon Mar 20 19:53:58 CST 2017

begin timer=Mon Mar 20 19:54:00 CST 2017

  end timer=Mon Mar 20 19:54:00 CST 2017

 scheduleAtFixedRate方法输出结果:

现在执行时间: Mon Mar 20 19:55:02 CST 2017

计划执行时间: Mon Mar 20 19:54:42 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:02 CST 2017

  end timer=Mon Mar 20 19:55:02 CST 2017

begin timer=Mon Mar 20 19:55:04 CST 2017

  end timer=Mon Mar 20 19:55:04 CST 2017

begin timer=Mon Mar 20 19:55:06 CST 2017

  end timer=Mon Mar 20 19:55:06 CST 2017

begin timer=Mon Mar 20 19:55:08 CST 2017

  end timer=Mon Mar 20 19:55:08 CST 2017

相信你已经看得很明白了scheduleAtFixedRate方法具有追赶性,他会把没执行的计划任务,在任务开始时,追赶重新执行完,而 schedule则不具备追赶性,从当前时间开始往后间隔执行任务

总结:

    Timer不支持多线程,所有挂在Timer下的任务都是单线程的,任务只能串行执行,如果其中一个任务执行时间过长,会影响到其他任务的执行,然后就可能会有各种接踵而来的问题。

   Timer的线程不捕获异常,TimerTask如果抛出异常,那么Timer唯一的进程就会挂掉,这样挂在Timer下的所有任务都会无法继续执行。

    经过以上分析,也就明白为什么jdk1.5中引入了并发包,这里面提供的ScheduledExecutorService。具体实现类是:ScheduledThreadPoolExecutor。ScheduledThreadPoolExecutor支持多线程,同时在线程中对异常进行了捕获。所以是Timer的完美替换者。

    下面是一个简单实例

 
public class Task1 extends TimerTask{

@SuppressWarnings("deprecation")
@Override
public void run() {
System.out.println("----task1 start--------"+new Date().toLocaleString());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("----3s later, task1 end--------"+new Date().toLocaleString());
}
}

 

    

public class Task2 extends TimerTask{  
  
    @SuppressWarnings("deprecation")  
    @Override  
    public void run() {  
        System.out.println("----task2 start--------"+new Date().toLocaleString());  
        try {  
            Thread.sleep(5000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println("----5s later, task2 end--------"+new Date().toLocaleString());  
    }  
} 

 

	public static void main(String[] args) {

		ScheduledExecutorService pool = Executors.newScheduledThreadPool(2);//启用2个线程
		
		Task1 t1 = new Task1();
		// 立即执行,任务消耗3秒,执行结束后等待2秒,【有空余线程时】,再次执行该任务
		pool.scheduleWithFixedDelay(t1, 0, 2, TimeUnit.SECONDS);
		
		// 立即执行,任务消耗5秒,执行结束后等待2秒,【有空余线程时】,再次执行该任务
		Task2 t2 = new Task2();
		pool.scheduleWithFixedDelay(t2, 0, 2, TimeUnit.SECONDS);
		
	}

 

猜你喜欢

转载自zrgzrgzrgzrg.iteye.com/blog/2364200