zoukankan      html  css  js  c++  java
  • Java多线程编程核心技术--定时器

    Timer类主要负责计划任务,也就是在指定的时间开始执行某一个任务。

    方法schedule(TimerTask task, Date time)
    public class Task {
    	private static Timer timer = new Timer();
    	static public class MyTask extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task运行了,时间为:" + new Date());
    		}
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask myTask = new MyTask();
    			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString = "2016-07-09 21:30:19";
    			Date date = sdf.parse(dateString);
    			System.out.println("main启动时间为:" + new Date());
    			timer.schedule(myTask, date);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main启动时间为:Sat Jul 09 21:28:54 CST 2016
    Task运行了,时间为:Sat Jul 09 21:30:19 CST 2016
    

    任务虽然执行完了,但是进程还没有销毁。

    创建Timer的源码如下:

    public Timer() {
        this("Timer-" + serialNumber());
    }
     
    public Timer(String name) {
        thread.setName(name);
        thread.start();
    }   
    

    由构造方法可知,创建一个Timer就是启动一个新的线程,这个新启动的线程并不是守护线程,它就一直在运行。

    将新创建的timer改成守护线程如下:

    public class Task {
    	private static Timer timer = new Timer(true);
    	static public class MyTask extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task运行了,时间为:" + new Date());
    		}
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask myTask = new MyTask();
    			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString = "2016-07-09 21:42:19";
    			Date date = sdf.parse(dateString);
    			System.out.println("main启动时间为:" + new Date());
    			timer.schedule(myTask, date);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    此时控制台打印结果如下:

    main启动时间为:Sat Jul 09 21:41:59 CST 2016
    

    由于新创建的Timer线程是守护线程,main线程运行完成之后迅速结束当前进程的运行。TimerTask中的任务不会得到执行。


    若执行任务的时间早于当前时间,则会立即执行任务。

    public class Task {
    	private static Timer timer = new Timer();
    	static public class MyTask extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task运行了,时间为:" + new Date());
    		}
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask myTask = new MyTask();
    			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString = "2016-07-09 21:42:19";
    			Date date = sdf.parse(dateString);
    			System.out.println("main启动时间为:" + new Date());
    			timer.schedule(myTask, date);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main启动时间为:Sat Jul 09 21:47:29 CST 2016
    Task运行了,时间为:Sat Jul 09 21:47:29 CST 2016
    

    多个TimerTask任务及延时的测试

    Timer中允许有多个TimerTask任务

    public class Task {
    	private static Timer timer = new Timer();
    	static public class MyTask1 extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task1运行了,时间为:" + new Date());
    		}
    	}
    	static public class MyTask2 extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task2运行了,时间为:" + new Date());
    		}
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask1 myTask1 = new MyTask1();
    			MyTask2 myTask2 = new MyTask2();
    			SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString1 = "2016-07-09 22:04:19";
    			String dateString2 = "2016-07-09 22:05:19";
    			Date date1 = sdf1.parse(dateString1);
    			Date date2 = sdf2.parse(dateString2);
    			System.out.println("main启动时间为:" + new Date());
    			timer.schedule(myTask1, date1);
    			timer.schedule(myTask2, date2);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main启动时间为:Sat Jul 09 22:04:09 CST 2016
    Task1运行了,时间为:Sat Jul 09 22:04:19 CST 2016
    Task2运行了,时间为:Sat Jul 09 22:05:19 CST 2016
    

    TimerTask是以队列的方式一个一个被顺序执行的,所以执行的时间有可能和预期的时间不一致。如果前面的任务耗时较长,后面的任务执行时间有可能被推迟。

    public class Task {
    	private static Timer timer = new Timer();
    	static public class MyTask1 extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task1运行了,时间为:" + new Date());
    			try {
    				Thread.sleep(20000);
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    	}
    	static public class MyTask2 extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task2运行了,时间为:" + new Date());
    		}
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask1 myTask1 = new MyTask1();
    			MyTask2 myTask2 = new MyTask2();
    			SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString1 = "2016-07-09 22:08:19";
    			String dateString2 = "2016-07-09 22:08:29";
    			Date date1 = sdf1.parse(dateString1);
    			Date date2 = sdf2.parse(dateString2);
    			System.out.println("main启动时间为:" + new Date());
    			timer.schedule(myTask1, date1);
    			timer.schedule(myTask2, date2);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main启动时间为:Sat Jul 09 22:08:06 CST 2016
    Task1运行了,时间为:Sat Jul 09 22:08:19 CST 2016
    Task2运行了,时间为:Sat Jul 09 22:08:39 CST 2016
    

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

    该方法的作用是在指定的日期之后,按指定的时间间隔周期性地无限循环地执行某一个任务

    public class Main {
    	static public class MyTask extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("开始运行,时间:" + new Date());
    		}
    		public static void main(String[] args) {
    			try {
    				MyTask task = new MyTask();
    				SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    				Timer timer = new Timer();
    				String dateString = "2016-07-09 22:17:55";
    				Date date = sdf.parse(dateString);
    				System.out.println("main开始执行时间:" + new Date());
    				timer.schedule(task, date, 4000);
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    	}
    }
    

    程序执行结果如下:

    main开始执行时间:Sat Jul 09 22:17:30 CST 2016
    开始运行,时间:Sat Jul 09 22:17:55 CST 2016
    开始运行,时间:Sat Jul 09 22:17:59 CST 2016
    开始运行,时间:Sat Jul 09 22:18:03 CST 2016
    开始运行,时间:Sat Jul 09 22:18:07 CST 2016
    ......
    

    TimerTask类的cancel()方法

    TimerTask类的cancel()方法的作用是将自身从任务队列中清除

    public class Task {
    	private static Timer timer = new Timer();
    	static public class MyTask1 extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task1运行了,时间为:" + new Date());
    			this.cancel();
    		}
    	}
    	static public class MyTask2 extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task2运行了,时间为:" + new Date());
    		}
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask1 myTask1 = new MyTask1();
    			MyTask2 myTask2 = new MyTask2();
    			SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString1 = "2016-07-09 22:08:19";
    			String dateString2 = "2016-07-09 22:08:29";
    			Date date1 = sdf1.parse(dateString1);
    			Date date2 = sdf2.parse(dateString2);
    			System.out.println("main启动时间为:" + new Date());
    			timer.schedule(myTask1, date1, 4000);
    			timer.schedule(myTask2, date2, 4000);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main启动时间为:Sat Jul 09 22:24:15 CST 2016
    Task1运行了,时间为:Sat Jul 09 22:24:15 CST 2016
    Task2运行了,时间为:Sat Jul 09 22:24:15 CST 2016
    Task2运行了,时间为:Sat Jul 09 22:24:19 CST 2016
    Task2运行了,时间为:Sat Jul 09 22:24:23 CST 2016
    ......
    

    Timer类的cancel()方法

    Timer类的cancel()方法的作用是将任务队列中的全部任务清除

    public class Task {
    	private static Timer timer = new Timer();
    	static public class MyTask1 extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task1运行了,时间为:" + new Date());
    			timer.cancel();
    		}
    	}
    	static public class MyTask2 extends TimerTask{
    		@Override
    		public void run() {
    			System.out.println("Task2运行了,时间为:" + new Date());
    		}
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask1 myTask1 = new MyTask1();
    			MyTask2 myTask2 = new MyTask2();
    			SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString1 = "2016-07-09 22:08:19";
    			String dateString2 = "2016-07-09 22:08:29";
    			Date date1 = sdf1.parse(dateString1);
    			Date date2 = sdf2.parse(dateString2);
    			System.out.println("main启动时间为:" + new Date());
    			timer.schedule(myTask1, date1, 4000);
    			timer.schedule(myTask2, date2, 4000);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main启动时间为:Sat Jul 09 22:26:21 CST 2016
    Task1运行了,时间为:Sat Jul 09 22:26:21 CST 2016
    

    全部任务都被清除,并且进程被销毁。


    Timer类的cancel()方法注意事项
    public class Main {
    	static int i = 0;
    	static public class MyTask extends TimerTask{
    
    		@Override
    		public void run() {
    			System.out.println("正常执行:" + i);
    		}
    	}
    	public static void main(String[] args) throws ParseException {
    		while (true) {
    			i++;
    			Timer timer = new Timer();
    			MyTask task = new MyTask();
    			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString = "2016-07-09 22:32:55";
    			Date date = sdf.parse(dateString);
    			timer.schedule(task, date);
    			timer.cancel();
    		}
    	}
    }
    

    程序运行结果如下:

    ......
    正常执行:12466
    正常执行:12486
    正常执行:12592
    正常执行:12656
    正常执行:12773
    正常执行:15554
    正常执行:15968
    ......
    

    这是因为Timer类中的cancel()没有争抢到queue锁,所以TimerTask类中的任务继续正常执行。


    方法schedule(TimerTask task, long delay)的使用

    方法schedule(TimerTask task, long delay)的作用是以当前时间为基准延迟delay毫秒数执行

    public class Main {
    	static public class MyTask extends TimerTask{
    
    		@Override
    		public void run() {
    			System.out.println("执行时间:" + new Date());
    		}
    	}
    	public static void main(String[] args) throws ParseException {
    		Timer timer = new Timer();
    		MyTask task = new MyTask();
    		System.out.println("当前时间:" + new Date());
    		timer.schedule(task, 5000);
    	}
    }
    

    程序运行结果如下:

    当前时间:Sat Jul 09 22:37:45 CST 2016
    执行时间:Sat Jul 09 22:37:50 CST 2016
    

    schedule(task, delay, period)的使用

    schedule(task, delay, period)的作用是以当前时间为基准延迟delay毫秒数,以period毫秒数为间隔无限循环周期执行

    public class Main {
    	static public class MyTask extends TimerTask{
    
    		@Override
    		public void run() {
    			System.out.println("执行时间:" + new Date());
    		}
    	}
    	public static void main(String[] args) throws ParseException {
    		Timer timer = new Timer();
    		MyTask task = new MyTask();
    		System.out.println("当前时间:" + new Date());
    		timer.schedule(task, 5000, 2000);
    	}
    }
    

    程序运行结果如下:

    当前时间:Sat Jul 09 22:40:14 CST 2016
    执行时间:Sat Jul 09 22:40:19 CST 2016
    执行时间:Sat Jul 09 22:40:21 CST 2016
    执行时间:Sat Jul 09 22:40:23 CST 2016
    ......
    

    schedule方法任务不延时
    public class Main {
    	private static Timer timer = new Timer();
    	private static int runCount = 0;
    	static public class MyTask extends TimerTask{
    
    		@Override
    		public void run() {
    			try {
    				System.out.println("begin run," + new Date());
    				Thread.sleep(1000);
    				System.out.println("end run," + new Date());
    				runCount++;
    				if (runCount == 5) {
    					timer.cancel();
    				}
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    		
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask task = new MyTask();
    			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString = "2016-07-10 10:26:35";
    			Date date = sdf.parse(dateString);
    			System.out.println("main开始时间:" + new Date());
    			timer.schedule(task, date, 3000);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main开始时间:Sun Jul 10 10:26:27 CST 2016
    begin run,Sun Jul 10 10:26:35 CST 2016
    end run,Sun Jul 10 10:26:36 CST 2016
    begin run,Sun Jul 10 10:26:38 CST 2016
    end run,Sun Jul 10 10:26:39 CST 2016
    begin run,Sun Jul 10 10:26:41 CST 2016
    end run,Sun Jul 10 10:26:42 CST 2016
    begin run,Sun Jul 10 10:26:44 CST 2016
    end run,Sun Jul 10 10:26:45 CST 2016
    begin run,Sun Jul 10 10:26:47 CST 2016
    end run,Sun Jul 10 10:26:48 CST 2016
    

    在不延时的情况下,如果执行任务的时间没有被延时,则下一次执行任务的时间是上一次任务的开始时间加上delay时间。


    schedule方法任务延时
    public class Main {
    	private static Timer timer = new Timer();
    	private static int runCount = 0;
    	static public class MyTask extends TimerTask{
    
    		@Override
    		public void run() {
    			try {
    				System.out.println("begin run," + new Date());
    				Thread.sleep(5000);//任务耗时5秒
    				System.out.println("end run," + new Date());
    				runCount++;
    				if (runCount == 5) {
    					timer.cancel();
    				}
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    		
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask task = new MyTask();
    			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString = "2016-07-10 17:00:00";
    			Date date = sdf.parse(dateString);
    			System.out.println("main开始时间:" + new Date());
    			timer.schedule(task, date, 3000);//周期为3秒
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main开始时间:Sun Jul 10 16:59:31 CST 2016
    begin run,Sun Jul 10 17:00:00 CST 2016
    end run,Sun Jul 10 17:00:05 CST 2016
    begin run,Sun Jul 10 17:00:05 CST 2016
    end run,Sun Jul 10 17:00:10 CST 2016
    begin run,Sun Jul 10 17:00:10 CST 2016
    end run,Sun Jul 10 17:00:15 CST 2016
    begin run,Sun Jul 10 17:00:15 CST 2016
    end run,Sun Jul 10 17:00:20 CST 2016
    begin run,Sun Jul 10 17:00:20 CST 2016
    end run,Sun Jul 10 17:00:25 CST 2016
    

    任务执行周期为3秒,任务每次执行耗时5秒。从运行结果看,如果执行任务的时间被延时,那么下一次任务的执行时间以上一次任务“结束”时的时间为参考来计算。


    scheduleAtFixedRate方法任务不延时
    public class Main {
    	private static Timer timer = new Timer();
    	private static int runCount = 0;
    	static public class MyTask extends TimerTask{
    
    		@Override
    		public void run() {
    			try {
    				System.out.println("begin run," + new Date());
    				Thread.sleep(2000);//任务耗时2秒
    				System.out.println("end run," + new Date());
    				runCount++;
    				if (runCount == 5) {
    					timer.cancel();
    				}
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    		
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask task = new MyTask();
    			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString = "2016-07-10 17:18:00";
    			Date date = sdf.parse(dateString);
    			System.out.println("main开始时间:" + new Date());
    			timer.scheduleAtFixedRate(task, date, 3000);//周期为3秒
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main开始时间:Sun Jul 10 17:17:51 CST 2016
    begin run,Sun Jul 10 17:18:00 CST 2016
    end run,Sun Jul 10 17:18:02 CST 2016
    begin run,Sun Jul 10 17:18:03 CST 2016
    end run,Sun Jul 10 17:18:05 CST 2016
    begin run,Sun Jul 10 17:18:06 CST 2016
    end run,Sun Jul 10 17:18:08 CST 2016
    begin run,Sun Jul 10 17:18:09 CST 2016
    end run,Sun Jul 10 17:18:11 CST 2016
    begin run,Sun Jul 10 17:18:12 CST 2016
    end run,Sun Jul 10 17:18:14 CST 2016
    

    schedule和scheduleAtFixedRate的区别在于,如果指定开始执行的时间在当前系统运行时间之前,scheduleAtFixedRate会把已经过去的时间也作为周期执行,而schedule不会把过去的时间算上。


    scheduleAtFixedRate方法任务延时
    public class Main5 {
    	private static Timer timer = new Timer();
    	private static int runCount = 0;
    	static public class MyTask extends TimerTask{
    
    		@Override
    		public void run() {
    			try {
    				System.out.println("begin run," + new Date());
    				Thread.sleep(5000);//任务耗时5秒
    				System.out.println("end run," + new Date());
    				runCount++;
    				if (runCount == 5) {
    					timer.cancel();
    				}
    			} catch (Exception e) {
    				e.printStackTrace();
    			}
    		}
    		
    	}
    	public static void main(String[] args) {
    		try {
    			MyTask task = new MyTask();
    			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    			String dateString = "2016-07-10 17:21:40";
    			Date date = sdf.parse(dateString);
    			System.out.println("main开始时间:" + new Date());
    			timer.scheduleAtFixedRate(task, date, 3000);//周期为3秒
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

    程序运行结果如下:

    main开始时间:Sun Jul 10 17:21:35 CST 2016
    begin run,Sun Jul 10 17:21:40 CST 2016
    end run,Sun Jul 10 17:21:45 CST 2016
    begin run,Sun Jul 10 17:21:45 CST 2016
    end run,Sun Jul 10 17:21:50 CST 2016
    begin run,Sun Jul 10 17:21:50 CST 2016
    end run,Sun Jul 10 17:21:55 CST 2016
    begin run,Sun Jul 10 17:21:55 CST 2016
    end run,Sun Jul 10 17:22:00 CST 2016
    begin run,Sun Jul 10 17:22:00 CST 2016
    end run,Sun Jul 10 17:22:05 CST 2016
    

    任务开始时间间隔为5秒。

  • 相关阅读:
    JAVA maven 仓库 基础命令
    JAVA maven 环境变量配置
    JAVA jdk 环境变量配置
    kafka 环境搭建
    java servlet 基础
    java idea 配置tomcat
    java tomcat服务器
    java io流
    java 字符流
    【火炉炼AI】深度学习005-简单几行Keras代码解决二分类问题
  • 原文地址:https://www.cnblogs.com/umgsai/p/5600106.html
Copyright © 2011-2022 走看看