Java多线程再升级(二)——计时器

Java多线程再升级(二)——计时器

如果不出意外,这一篇应该是java多线程内容的倒数第三篇,后续应该会有一个再升级篇的一篇以及一篇番外篇(二),java多线程的内容就算是暂时的告一段落了。
这一篇的内容是关于java计时器的内容,内容不难,但是需要一点耐心以及细心,最重要的是多做尝试,自然就能理解其中的内容。

定时器Timer

在java的类中,有一个主要负责计划任务的类就是Timer。所谓的计划任务,就是让任务在指定的时间执行。
Timer的主要作用是设置计划任务,但是封装任务的类却是TimerTask类。执行的任务需要放入TimerTask的子类中。
如图所示:
Java多线程再升级(二)——计时器_第1张图片
这样才能正确的设置和使用Timer。
下面我们来介绍几种方法:

Schedule(TimerTask task,Date time)方法

这个方法的作用是在指定的日期执行一次某任务。
使用方法如下所示:

public class Test_thread{
	private static Timer timer=new Timer();
	static public class MyTask1 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask1 运行了!时间为:"+new Date());
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	static public class MyTask2 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask2 运行了!时间为:"+new Date());
		}
		
	}
	public static void main(String[] args) throws InterruptedException{
		try {
			MyTask1 task1=new MyTask1();
			MyTask2 task2=new MyTask2();
			SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			SimpleDateFormat sdf2=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String dateString1="2018-10-12 11:55:00";
			String dateString2="2018-10-12 11:56:00";
			Date dateRef1=sdf1.parse(dateString1);
			Date dateRef2=sdf2.parse(dateString2);
			timer.schedule(task1, dateRef1);
			timer.schedule(task2, dateRef2);
			Thread.sleep(2000);
			System.out.println("字符串1时间:"+dateRef1.toLocaleString()
			+"  当前时间:"+new Date().toLocaleString());
			System.out.println("字符串2时间:"+dateRef2.toLocaleString()
			+"  当前时间:"+new Date().toLocaleString());
		}catch(ParseException e) {
			e.printStackTrace();
		}
	}
}

运行结果如下图所示:
Java多线程再升级(二)——计时器_第2张图片
在这个程序中,我们输入的时间均早于我运行程序时候的时间,在这种情况下就会立即执行task任务,同时,从结果中我们可以看出,虽然我们已经很早的就将task2的任务放入到schedual中去运行,但是却很晚才执行完毕。
之所以有这样的结果是因为TimerTask是以队列的方式顺序执行的,所以后面的任务很有可能因为前面的任务的执行时间过长,导致后面的任务时间也被延迟。如果用同一个计时器就会导致这样的结果,当然只要使用不同的计时器就要避免这种情况的发生。
大家可以尝试修改时间改在大家现在的时间的前和后,相信会很快了解计时器的用法,对这个有很大的收获。

Schedule(TimerTask task,Date firstTime,long period)

该方法的作用是在指定的如期后,按照指定的时间间隔无限的执行某一任务。
字面上很好理解,但是实际操作过程中可能会有一些问题,例如下面的程序:

public class Test_thread{
	private static Timer timer=new Timer();
	private static Timer timer2=new Timer();
	static public class MyTask1 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask1 运行了!时间为:"+new Date());
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}	public static void main(String[] args) throws InterruptedException{
		try {
			MyTask1 task1=new MyTask1();
			SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String dateString1="2018-10-12 11:55:00";
			Date dateRef1=sdf1.parse(dateString1);
			
			System.out.println("字符串1时间:"+dateRef1.toLocaleString()
			+"  当前时间:"+new Date().toLocaleString());
			timer.schedule(task1, dateRef1,4000);
		}catch(ParseException e) {
			e.printStackTrace();
		}
	}
}

执行结果如下所示:
Java多线程再升级(二)——计时器_第3张图片
可以看到原本设定的每四秒执行一次的结果,被对象中的沉睡打破,变为每五秒执行一次。如果把对象中的沉睡语句注释掉,就会看到又能够正常的执行了。
同样,当执行时间早于当前时间,就会立即执行。

TimeTask类中的Cancel方法

作用是将自身从队列中清除。

public class Test_thread{
	private static Timer timer=new Timer();
	private static Timer timer2=new Timer();
	static public class MyTask1 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask1 运行了!时间为:"+new Date());
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	static public class MyTask2 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask2 运行了!时间为:"+new Date());
		}
		
	}
	public static void main(String[] args) throws InterruptedException{
		try {
			MyTask1 task1=new MyTask1();
			MyTask2 task2=new MyTask2();
			SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String dateString1="2018-10-12 11:55:00";
			Date dateRef1=sdf1.parse(dateString1);
			timer.schedule(task1, dateRef1,2000);
			timer.schedule(task2, dateRef1,2000);
			System.out.println("字符串1时间:"+dateRef1.toLocaleString()
			+"  当前时间:"+new Date().toLocaleString());
			Thread.sleep(10000);
			System.out.println("现在关闭task1!");
			task1.cancel();
		}catch(ParseException e) {
			e.printStackTrace();
		}
	}
}

运行结果:
Java多线程再升级(二)——计时器_第4张图片

Timer中的cancel方法

Timer中同样有cancel方法,但是与之不同的是,timer中的cancel方法是将所有的task清除掉,如下所示:

public class Test_thread{
	private static Timer timer=new Timer();
	private static Timer timer2=new Timer();
	static public class MyTask1 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask1 运行了!时间为:"+new Date());
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	static public class MyTask2 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask2 运行了!时间为:"+new Date());
		}
		
	}
	public static void main(String[] args) throws InterruptedException{
		try {
			MyTask1 task1=new MyTask1();
			MyTask2 task2=new MyTask2();
			SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String dateString1="2018-10-12 11:55:00";
			Date dateRef1=sdf1.parse(dateString1);
			timer.schedule(task1, dateRef1,2000);
			timer.schedule(task2, dateRef1,2000);
			System.out.println("字符串1时间:"+dateRef1.toLocaleString()
			+"  当前时间:"+new Date().toLocaleString());
			Thread.sleep(10000);
			System.out.println("现在关闭task1!");
			timer.cancel();
		}catch(ParseException e) {
			e.printStackTrace();
		}
	}
}

执行结果:
Java多线程再升级(二)——计时器_第5张图片

schedule(TimerTask task,long delay)方法

在当前时间的基础上延后delay方法以后,执行一次TimerTask任务。
public class Test_thread{
private static Timer timer=new Timer();
private static Timer timer2=new Timer();
static public class MyTask1 extends TimerTask{
@Override
public void run() {
System.out.println(“MyTask1 运行了!时间为:”+new Date());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
public static void main(String[] args) throws InterruptedException{
		MyTask1 task1=new MyTask1();
		SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		timer.schedule(task1, 2000);			
		Thread.sleep(10000);
}

}
执行结果:
Java多线程再升级(二)——计时器_第6张图片

Schedule(TimerTask task,long delay,long period)

在上一个方法的基础上,每隔一段时间执行一次任务:

public class Test_thread{
	private static Timer timer=new Timer();
	private static Timer timer2=new Timer();
	static public class MyTask1 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask1 运行了!时间为:"+new Date());
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	public static void main(String[] args) throws InterruptedException{
			MyTask1 task1=new MyTask1();
			SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			timer.schedule(task1, 2000,2000);			
			Thread.sleep(10000);
	}
}

Java多线程再升级(二)——计时器_第7张图片

scheduleAtFixedRate(TimerTask task,Date firstTime,long period)方法

scheduleAtFixedRate是一种和schedule方法很类似的方法,但是,在非延时的情况下,scheduleAtFixedRate是参考上一次任务的“结束”时间来计算的。而不是schedule方法中的上一次任务的开始时间来计算的。
延时的情况两者是相同的,都是以结束时间来计算的。
如下所示:

public class Test_thread{
	private static Timer timer=new Timer();
	private static Timer timer2=new Timer();
	static public class MyTask1 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask1 运行了!时间为:"+new Date());
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
	public static void main(String[] args) throws InterruptedException{
		try {
			MyTask1 task1=new MyTask1();
			SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String dateString1="2018-10-12 11:55:00";
			Date dateRef1=sdf1.parse(dateString1);
			System.out.println("现在启动Task1:"+new Date().toLocaleString());
			timer.scheduleAtFixedRate(task1, dateRef1, 3000);			
		}catch(ParseException e) {
			e.printStackTrace();
		}
	}
}

运行结果:
Java多线程再升级(二)——计时器_第8张图片
从结果可以看出,如果执行任务的时间没有被时延,则下一次执行任务的时间是上一次任务的开始时间加上delay时间。
scheduleAtFixedRate还有一个特性是追赶性。什么是追赶性?如果执行时间早于现在的时间,那么该方法会将从执行时间到现在时间之间的任务自动的执行。知道赶上当前时间即结束当前任务:

public class Test_thread{
	private static Timer timer=new Timer();
	private static Timer timer2=new Timer();
	static public class MyTask1 extends TimerTask{
		@Override
		public void run() {
			System.out.println("MyTask1 运行了!时间为:"+new Date());
		}
		
	}
	public static void main(String[] args) throws InterruptedException{
		try {
			MyTask1 task1=new MyTask1();
			SimpleDateFormat sdf1=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String dateString1="2019-8-12 15:18:00";
			Date dateRef1=sdf1.parse(dateString1);	
			System.out.println("字符串1时间:"+dateRef1.toLocaleString()
			+"  当前时间:"+new Date().toLocaleString());
			timer.scheduleAtFixedRate(task1, dateRef1, 5000);
			
			Thread.sleep(10000);
		}catch(ParseException e) {
			e.printStackTrace();
		}
	}
}

结果如图所示:
Java多线程再升级(二)——计时器_第9张图片
请尝试这个程序的小伙伴,一定要调整好时间,大家就会明白所谓的追赶性究竟是什么东西了。当然schedule方法是没有追赶性的,它的执行是从当前时间开始的,但是不会补上以前没有执行的任务,这就是两者的区别。

以上就是java多线程计时器的内容,计时器的用途广泛,完全可以使用在很多的场合,但是有很多的细节需要大家注意。Java多线程倒数第三篇文章到此结束。

你可能感兴趣的:(java技术,计时器,java多线程)