© 版权声明:本文为博主原创文章,转载请注明出处
1.Timer:有且仅有一个后台线程对多个业务线程进行定时定频率的调度
2.schedule
schedule(task, time):在时间等于或超过time的时候执行且仅执行一次task
schedule(task, time, period):时间等于或超过time时首次执行task,之后每隔period毫秒重复执行一次task
schedule(task, delay):等待delay毫秒后执行且仅执行一次task
schedule(task, delay, period):等待delay毫秒后首次执行delay,之后每隔period毫秒重复执行一次task
3.scheduleAtFixedRate
scheduleAtFixedRate(task, time, period):同schedule(task, time, period)
scheduleAtFixedRate(task, delay, period):同schedule(task, delay, period)
4.schedule和scheduleAtFixedRate区别
4.1 首次执行的时间早于当前时间
- schedule会以当前时间为首次执行时间,然后继续执行
package org.timer.test;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Timer;import java.util.TimerTask;/** * schedule和scheduleAtFixedRate不同 * */public class Difference { public static void main(String[] args) { // 获取当前时间 Calendar calendar = Calendar.getInstance(); final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(format.format(calendar.getTime())); // 创建Timer对象 Timer timer = new Timer(); /** * 首次计划执行的时间早于当前时间 */ // 将时间往前推6s calendar.add(Calendar.SECOND, -6); // schedule timer.schedule(new TimerTask() { @Override public void run() { System.out.println("执行时间为:" + format.format(scheduledExecutionTime())); } }, calendar.getTime(), 2000L); } }
- scheduleAtFixedRate仍以计划时间为准,连续执行数次,直至与当前时间相同
package org.timer.test;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Timer;import java.util.TimerTask;/** * schedule和scheduleAtFixedRate不同 * */public class Difference { public static void main(String[] args) { // 获取当前时间 Calendar calendar = Calendar.getInstance(); final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(format.format(calendar.getTime())); // 创建Timer对象 Timer timer = new Timer(); /** * 首次计划执行的时间早于当前时间 */ // 将时间往前推6s calendar.add(Calendar.SECOND, -6); // scheduleAtFixedRate timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println("执行时间为:" + format.format(scheduledExecutionTime())); } }, calendar.getTime(), 2000L); } }
4.2 任务执行所需时间超出任务的执行周期间隔
- schedule会等待任务执行完成
package org.timer.test;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Timer;import java.util.TimerTask;/** * schedule和scheduleAtFixedRate不同 * */public class Difference { public static void main(String[] args) { // 获取当前时间 Calendar calendar = Calendar.getInstance(); final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(format.format(calendar.getTime())); // 创建Timer对象 Timer timer = new Timer(); /** * 任务执行所需时间超出任务的执行周期间隔 */ // schedule timer.schedule(new TimerTask() { @Override public void run() { // 睡眠3s try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("执行时间为:" + format.format(scheduledExecutionTime())); } }, calendar.getTime(), 2000L); } }
- scheduleAtFixedRate仍会安装任务的执行周期间隔执行,因此存在并发执行的问题
package org.timer.test;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Timer;import java.util.TimerTask;/** * schedule和scheduleAtFixedRate不同 * */public class Difference { public static void main(String[] args) { // 获取当前时间 Calendar calendar = Calendar.getInstance(); final DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println(format.format(calendar.getTime())); // 创建Timer对象 Timer timer = new Timer(); /** * 任务执行所需时间超出任务的执行周期间隔 */ // scheduleAtFixedRate timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { // 睡眠3s try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("执行时间为:" + format.format(scheduledExecutionTime())); } }, calendar.getTime(), 2000L); } }
5.其他方法
- scheduleExecutionTime:返回此任务最近实际执行的已安排执行的时间
- cancel:终止此定时器,丢弃所有当前已安排的任务
- purge:从此计时器的任务队列中移除所有已取消的任务,并返回从队列中取消的任务数
6.实例
需求:创建两个机器人,跳舞机器人和灌水机器人
- 灌水机器人每隔1s灌一次水,灌满后停止工作
- 跳舞机器人在水灌满之前每隔2s跳一次舞,水灌满后等待2s,停止工作
6.1 DancingRobot.java
package org.timer.test;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.TimerTask;/** * 跳舞机器人:每隔2s跳一次舞,水灌满后继续跳舞2s然后停止工作 * */public class DancingRobot extends TimerTask { @Override public void run() { // 获取最近的一次任务执行时间,并将其格式化 DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Schedule exec time is : " + format.format(scheduledExecutionTime())); // 跳舞 System.out.println("Dancing happily!"); }}
6.2 WaterRobot.java
package org.timer.test;import java.util.Timer;import java.util.TimerTask;/** * 灌水机器人, * @author chen * */public class WaterRoot extends TimerTask { // 最大容量无5L private int bucketCapacity = 0; private Timer timer; public WaterRoot(Timer timer) { this.timer = timer; } @Override public void run() { if (bucketCapacity < 5) { System.out.println("Add 1L water into the bucket!"); bucketCapacity++; } else { System.out.println("The number of canceled task in timer is : " + timer.purge()); // 水满之后停止执行 cancel(); System.out.println("The waterRobot has been aborted"); System.out.println("The number of canceled task in timer is : " + timer.purge()); System.out.println("Current water is : " + bucketCapacity); // 等待2s,终止timer里面的所有内容 try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } timer.cancel(); } } }
6.3 Executor.java
package org.timer.test;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Calendar;import java.util.Timer;public class Executor { public static void main(String[] args) { // 创建Timer对象 Timer timer = new Timer(); // 获取当前时间 Calendar calendar = Calendar.getInstance(); DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current time is : " + format.format(calendar.getTime())); // 创建两个机器人对象 DancingRobot dr = new DancingRobot(); WaterRoot wr = new WaterRoot(timer); timer.schedule(dr, calendar.getTime(), 2000L); timer.scheduleAtFixedRate(wr, calendar.getTime(), 1000L); } }
6.4 效果预览
7.Timer的不足
7.1 Timer有且仅有一个线程去执行定时任务,如果存在多个任务,且任务时间过长,会导致执行结果与预期不同
7.2 如果TimerTask抛出RuntimeException,Timer会停止所有任务的运行
7.3 综上所述:对时效性要求较高的多任务并发作业和对复杂的任务调度最好不要使用Timer,可使用Quartz。
参考: