Java多线程编程(五)定时器Timer
一、定时器Timer的使用
在JDK库中Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某一个任务。Timer类的主要作用就是设置计划任务,但封装任务的类确实TimerTask类,执行计划任务的代码要放入TimerTask类的子类中,因为TimerTask是一个抽象类。
1.方法schedule(TimerTask task,Date time)的测试
该方法的任务是在指定的日期执行一次某一任务。
(1)执行任务的时间晚于当前时间:在未来执行的效果
示例:从输出结果可以看出,设定执行时间在29分钟,然后等待了47秒后,MyTask类里面的run()方法才执行。
package test; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run1 { private static Timer timer = new Timer(); 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");
String dateString = "2018-5-7 17:29:00"; Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:" + dateRef.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
timer.schedule(task, dateRef);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串时间:2018-5-7 17:29:00 当前时间:2018-5-7 17:28:13
运行了!时间为:Mon May 07 17:29:00 GMT+08:00 2018
虽然程序执行完了,但是进程还未销毁,仍然处于执行状态,这是因为,在new Timer()对象时,实际的构造方法是这样的:
public Timer() {
this("Timer-" + serialNumber());
}
public Timer(String name) {
thread.setName(name);
thread.start();
}
从构造方法可以看出,创建一个Timer对象就是启动一个新的线程,这个新启动的线程并不是守护线程,它一直在运行。
示例2:将private static Timer timer = new Timer();声明修改成private static Timer timer = new Timer(true);即让新创建的Timer改成守护线程,还是查看Timer()构造函数:
public Timer(boolean isDaemon) {
this("Timer-" + serialNumber(), isDaemon);
}
public Timer(String name, boolean isDaemon) {
thread.setName(name);
thread.setDaemon(isDaemon);
thread.start();
}
通过将新启动的线程设置为守护线程,就可以实现程序运行后迅速结束当前的进程,而且TimerTask中的任务也不再被运行,因为进程已经结束了,守护进程在进程开始前就已经创建了,当然没有检测到有进程在执行状态,所以就退出了。
字符串时间:2018-5-7 17:32:00 当前时间:2018-5-7 17:31:18
(2)计划时间早于当前时间:提前运行的效果
如果执行任务的时间早于当前时间,则立即执行task任务。
示例:从设置执行任务的时间在当前时间的前一分钟,通过输出可以看出,task任务立刻执行了。
字符串时间:2018-5-7 17:32:00 当前时间:2018-5-7 17:33:15
运行了!时间为:Mon May 07 17:33:15 GMT+08:00 2018
(3)多个TimerTask任务及延时的测试
示例1:TimerTask任务是以队列的方式一个一个被顺序执行的,所以执行的时间有可能和预期的时间不一致,因为前面的任务有可能消耗的时间比较长,则后面的任务运行的时间也会被延迟。
package test; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run2 { private static Timer timer = new Timer(); static public class MyTask1 extends TimerTask {
@Override
public void run() {
System.out.println("运行了!时间为:" + new Date());
}
} static public class MyTask2 extends TimerTask {
@Override
public void run() {
System.out.println("运行了!时间为:" + new Date());
}
} public static void main(String[] args) {
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-5-7 17:36:00";
String dateString2 = "2018-5-7 17:36:10"; Date dateRef1 = sdf1.parse(dateString1);
Date dateRef2 = sdf2.parse(dateString2); System.out.println("字符串1时间:" + dateRef1.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
System.out.println("字符串2时间:" + dateRef2.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString()); timer.schedule(task1, dateRef1);
timer.schedule(task2, dateRef2);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串1时间:2018-5-7 17:36:00 当前时间:2018-5-7 17:35:33
字符串2时间:2018-5-7 17:36:10 当前时间:2018-5-7 17:35:33
运行了!时间为:Mon May 07 17:36:00 GMT+08:00 2018
运行了!时间为:Mon May 07 17:36:10 GMT+08:00 2018
示例2:由于task1线程运行时间需要20秒的时间,因此影响了task2的执行时间,所以在task1任务执行完之后马上执行了task2任务。
package test; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run2Later { private static Timer timer = new Timer(); static public class MyTask1 extends TimerTask {
@Override
public void run() {
try {
System.out.println("1 begin 运行了!时间为:" + new Date());
Thread.sleep(20000);
System.out.println("1 end 运行了!时间为:" + new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} static public class MyTask2 extends TimerTask {
@Override
public void run() {
System.out.println("2 begin 运行了!时间为:" + new Date());
System.out.println("运行了!时间为:" + new Date());
System.out.println("2 end 运行了!时间为:" + new Date());
}
} public static void main(String[] args) {
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-5-7 17:40:00";
String dateString2 = "2018-5-7 17:40:10"; Date dateRef1 = sdf1.parse(dateString1);
Date dateRef2 = sdf2.parse(dateString2); System.out.println("字符串1时间:" + dateRef1.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
System.out.println("字符串2时间:" + dateRef2.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString()); timer.schedule(task1, dateRef1);
timer.schedule(task2, dateRef2);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串1时间:2018-5-7 17:40:00 当前时间:2018-5-7 17:39:16
字符串2时间:2018-5-7 17:40:10 当前时间:2018-5-7 17:39:16
1 begin 运行了!时间为:Mon May 07 17:40:00 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 17:40:20 GMT+08:00 2018
2 begin 运行了!时间为:Mon May 07 17:40:20 GMT+08:00 2018
运行了!时间为:Mon May 07 17:40:20 GMT+08:00 2018
2 end 运行了!时间为:Mon May 07 17:40:20 GMT+08:00 2018
2.方法schedule(TimerTask task,Date firstTime,long period)的测试
该方法的作用是在指定的日期之后,按指定的间隔周期性地无线循环地执行某一任务。
(1)计划时间晚于当前时间:在未来执行的效果
示例:从输出结果可以看出,在指定的时间开始运行任务,并且每隔4秒运行一次。
package test; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run {
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");
String dateString = "2018-5-7 17:45:00";
Timer timer = new Timer();
Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:" + dateRef.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
timer.schedule(task, dateRef, 4000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串时间:2018-5-7 17:45:00 当前时间:2018-5-7 17:44:24
运行了!时间为:Mon May 07 17:45:00 GMT+08:00 2018
运行了!时间为:Mon May 07 17:45:04 GMT+08:00 2018
运行了!时间为:Mon May 07 17:45:08 GMT+08:00 2018
运行了!时间为:Mon May 07 17:45:12 GMT+08:00 2018
...
(2)计划时间早于当前时间:提前运行的效果
示例:计划时间早于当前时间,会立即执行task任务。
字符串时间:2018-5-7 17:45:00 当前时间:2018-5-7 17:46:24
运行了!时间为:Mon May 07 17:46:24 GMT+08:00 2018
运行了!时间为:Mon May 07 17:46:28 GMT+08:00 2018
运行了!时间为:Mon May 07 17:46:32 GMT+08:00 2018
运行了!时间为:Mon May 07 17:46:36 GMT+08:00 2018
...
(3)任务执行时间被延时
示例:设置一个任务执行时间为5秒,但是间隔只有4秒,这种情况下,任务被延时,但还是一个一个按顺序运行。
package test; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run2_1 {
static public class MyTaskA extends TimerTask {
@Override
public void run() {
try {
System.out.println("A运行了!时间为:" + new Date());
Thread.sleep(5000);
System.out.println("A结束了!时间为:" + new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
try {
MyTaskA taskA = new MyTaskA();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2018-5-7 17:49:00";
Timer timer = new Timer();
Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:" + dateRef.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
timer.schedule(taskA, dateRef, 4000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串时间:2018-5-7 17:49:00 当前时间:2018-5-7 17:48:09
A运行了!时间为:Mon May 07 17:49:00 GMT+08:00 2018
A结束了!时间为:Mon May 07 17:49:05 GMT+08:00 2018
A运行了!时间为:Mon May 07 17:49:05 GMT+08:00 2018
A结束了!时间为:Mon May 07 17:49:10 GMT+08:00 2018
A运行了!时间为:Mon May 07 17:49:10 GMT+08:00 2018
A结束了!时间为:Mon May 07 17:49:15 GMT+08:00 2018
...
(4)TimerTask类的cancel()方法
TimerTask类的cancel()方法的作用是将自身从任务队列中清除。
示例:从输出可以看出,任务A在执行一次后,把自己从任务队列中清除了。(如果计划时间早于当前时间会有问题!)
package test; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run2 {
static public class MyTaskA extends TimerTask {
@Override
public void run() {
System.out.println("A运行了!时间为:" + new Date());
this.cancel();
}
} static public class MyTaskB extends TimerTask {
@Override
public void run() {
System.out.println("B运行了!时间为:" + new Date());
}
} public static void main(String[] args) {
try {
MyTaskA taskA = new MyTaskA();
MyTaskB taskB = new MyTaskB();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2018-5-7 17:49:00";
Timer timer = new Timer();
Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:" + dateRef.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
timer.schedule(taskA, dateRef, 4000);
timer.schedule(taskB, dateRef, 4000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串时间:2018-5-7 17:54:00 当前时间:2018-5-7 17:53:23
A运行了!时间为:Mon May 07 17:54:00 GMT+08:00 2018
B运行了!时间为:Mon May 07 17:54:00 GMT+08:00 2018
B运行了!时间为:Mon May 07 17:54:04 GMT+08:00 2018
B运行了!时间为:Mon May 07 17:54:08 GMT+08:00 2018
B运行了!时间为:Mon May 07 17:54:12 GMT+08:00 2018
B运行了!时间为:Mon May 07 17:54:16 GMT+08:00 2018
B运行了!时间为:Mon May 07 17:54:20 GMT+08:00 2018
...
(5)Timer类的cancel()方法
Timer类的cancel()方法的作用是将任务队列中的全部任务清空。
示例:任务A执行一次后,调用timer.cancel();将任务队列中的全部任务清空,并且结束了进程,进程被销毁了。
package test; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run3 {
private static Timer timer = new Timer(); static public class MyTaskA extends TimerTask {
@Override
public void run() {
System.out.println("A运行了!时间为:" + new Date());
timer.cancel();
}
} static public class MyTaskB extends TimerTask {
@Override
public void run() {
System.out.println("B运行了!时间为:" + new Date());
}
} public static void main(String[] args) {
try {
MyTaskA taskA = new MyTaskA();
MyTaskB taskB = new MyTaskB();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2018-5-7 17:57:00";
Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:" + dateRef.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
timer.schedule(taskA, dateRef, 4000);
timer.schedule(taskB, dateRef, 4000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串时间:2018-5-7 17:57:00 当前时间:2018-5-7 17:56:28
A运行了!时间为:Mon May 07 17:57:00 GMT+08:00 2018
(6)Timer类的cancel()方法注意事项
Timer类的cancel()方法有时并不一定会停止执行计划任务,而是正常执行。
示例:这是因为Timer类中的cancel()方法有时并没有争抢到queue锁,所以TimerTask类中的任务继续正常执行,结果中输出的数也不是连续的,也可以说明这一点。
package test; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run4 {
static int i = 0; static public class MyTask extends TimerTask {
@Override
public void run() {
System.out.println("正常执行了" + i);
}
} public static void main(String[] args) {
while (true) {
try {
i++;
Timer timer = new Timer();
MyTask task = new MyTask();
SimpleDateFormat sdf = new SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss");
String dateString = "2018-5-7 18:05:00"; Date dateRef = sdf.parse(dateString);
timer.schedule(task, dateRef);
timer.cancel();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
}
正常执行了541099
正常执行了592127
正常执行了655574
正常执行了809347
正常执行了834669
...
3.方法schedule(TimerTask task,long delay)的测试
该方法的作用是以执行schedule(TimerTask task,long delay)方法当前的时间为参考时间,在此时间基础上延迟指定的毫秒数后执行一次TimerTask任务。
示例:在执行完方法后,延迟7秒的时间,执行了task任务。
package test; import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run {
static public class MyTask extends TimerTask {
@Override
public void run() {
System.out.println("运行了!时间为:" + new Date());
}
}
public static void main(String[] args) {
MyTask task = new MyTask();
Timer timer = new Timer();
System.out.println("当前时间:" + new Date().toLocaleString());
timer.schedule(task, 7000);
}
}
当前时间:2018-5-7 18:10:57
运行了!时间为:Mon May 07 18:11:04 GMT+08:00 2018
4.方法schedule(TimerTask task,long delay,long period)的测试
该方法的作用是一执行schedule(TimerTask task,long delay,long period)方法未当前时间的参考时间,在此基础上延迟指定的毫秒数,并以某一时间间隔无限次数执行某一任务。
示例:在执行方法后的3秒时开始以5秒为间隔无限次数执行task任务。
package test; import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run {
static public class MyTask extends TimerTask {
@Override
public void run() {
System.out.println("运行了!时间为:" + new Date());
}
} public static void main(String[] args) {
MyTask task = new MyTask();
Timer timer = new Timer();
System.out.println("当前时间:"+new Date().toLocaleString());
timer.schedule(task, 3000,5000);
}
}
当前时间:2018-5-7 18:14:39
运行了!时间为:Mon May 07 18:14:42 GMT+08:00 2018
运行了!时间为:Mon May 07 18:14:47 GMT+08:00 2018
运行了!时间为:Mon May 07 18:14:52 GMT+08:00 2018
运行了!时间为:Mon May 07 18:14:57 GMT+08:00 2018
运行了!时间为:Mon May 07 18:15:02 GMT+08:00 2018
运行了!时间为:Mon May 07 18:15:07 GMT+08:00 2018
运行了!时间为:Mon May 07 18:15:12 GMT+08:00 2018
运行了!时间为:Mon May 07 18:15:17 GMT+08:00 2018
运行了!时间为:Mon May 07 18:15:22 GMT+08:00 2018
运行了!时间为:Mon May 07 18:15:27 GMT+08:00 2018
运行了!时间为:Mon May 07 18:15:32 GMT+08:00 2018
运行了!时间为:Mon May 07 18:15:37 GMT+08:00 2018
运行了!时间为:Mon May 07 18:15:42 GMT+08:00 2018
...
5.方法scheduleAtFixedRate(TimerTask task,Date firstTime,long period)的测试
方法schedule和方法scheduleAtFixedRate都会按顺序执行,所以不要考虑非线程安全的情况。
方法schedule和方法scheduleAtFixedRate主要的区别只在于不延时的情况。
使用schedule方法:如果执行任务的时间没有被延时,那么下一次任务的执行时间参考的是上一次任务的“开始”时的时间来计算的。
使用scheduleAtFixedRate方法:如果执行任务的时间没有被延时,那么下一次任务的执行时间参考的是上一次任务的“结束”时的时间来计算的。
延时的情况,则没有区别,都是下一次任务的执行时间参考的是上一次任务的“结束”时的时间来计算的。
(1)schedule方法任务不延时
示例:从输出结果可以看出,线程sleep的时间1000小于设置的时间间隔3000,因此不存在延时,在这种情况下,两次begin的时间间隔就是3秒。
package test.run; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run1 { private static Timer timer = new Timer();
private static int runCount = 0; static public class MyTask1 extends TimerTask {
@Override
public void run() {
try {
System.out.println("1 begin 运行了!时间为:" + new Date());
Thread.sleep(1000);
System.out.println("1 end 运行了!时间为:" + new Date());
runCount++;
if (runCount == 5) {
timer.cancel();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
try {
MyTask1 task1 = new MyTask1();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString1 = "2018-5-7 18:22:00";
Date dateRef1 = sdf1.parse(dateString1);
System.out.println("字符串1时间:" + dateRef1.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
timer.schedule(task1, dateRef1, 3000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串1时间:2018-5-7 18:22:00 当前时间:2018-5-7 18:21:15
1 begin 运行了!时间为:Mon May 07 18:22:00 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:22:01 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:22:03 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:22:04 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:22:06 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:22:07 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:22:09 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:22:10 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:22:12 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:22:13 GMT+08:00 2018
(2)schedule方法任务延时
示例:修改run方法中的sleep为5000>时间间隔设置2000,则从输出结果可以看出,下一次的begin的时间是上一次end的时间。
字符串1时间:2018-5-7 18:26:00 当前时间:2018-5-7 18:25:40
1 begin 运行了!时间为:Mon May 07 18:26:00 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:26:05 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:26:05 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:26:10 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:26:10 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:26:15 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:26:15 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:26:20 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:26:20 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:26:25 GMT+08:00 2018
(3)scheduleAtFixedRate方法任务不延时
示例1:sleep值为2000<时间间隔设置3000(且字符串时间要先于当前时间才可以),则从输出结果可以看出,如果执行任务的时间没有被延时,则这一次的begin和这一次的end之间相差时间间隔设置3000,而这一次的end和下一次的begin时间是一致的。
package test.run; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run3 { private static Timer timer = new Timer();
private static int runCount = 0; static public class MyTask1 extends TimerTask {
@Override
public void run() {
try {
System.out.println("1 begin 运行了!时间为:" + new Date());
Thread.sleep(2000);
System.out.println("1 end 运行了!时间为:" + new Date());
runCount++;
if (runCount == 5) {
timer.cancel();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} public static void main(String[] args) {
try {
MyTask1 task1 = new MyTask1();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString1 = "2018-5-7 18:32:00";
Date dateRef1 = sdf1.parse(dateString1);
System.out.println("字符串1时间:" + dateRef1.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
timer.scheduleAtFixedRate(task1, dateRef1, 3000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串1时间:2018-5-7 18:32:00 当前时间:2018-5-7 20:17:12
1 begin 运行了!时间为:Mon May 07 20:17:12 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:17:15 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:17:15 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:17:17 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:17:17 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:17:19 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:17:19 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:17:21 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:17:21 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:17:23 GMT+08:00 2018
示例2:字符串时间晚于当前时间的情况下,这种情况下,竟然是和schedule的不延时的情况是一致的。(这块很绕,就很气!应该是分了两种情况吧,具体实现看源码吧!)
字符串1时间:2018-5-7 20:32:00 当前时间:2018-5-7 20:31:17
1 begin 运行了!时间为:Mon May 07 20:32:00 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:32:02 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:32:03 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:32:05 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:32:06 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:32:08 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:32:09 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:32:11 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:32:12 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:32:14 GMT+08:00 2018
(4)scheduleAtFixedRate方法任务延时
示例:sleep值5000>时间间隔设置2000,则从输出结果可以看出,如果执行任务的时间被延时,那么下一次任务的执行时间以上一次任务“结束”时的时间为参考来计算。
字符串1时间:2018-5-7 18:37:00 当前时间:2018-5-7 18:36:42
1 begin 运行了!时间为:Mon May 07 18:37:00 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:37:05 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:37:05 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:37:10 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:37:10 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:37:15 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:37:15 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:37:20 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:37:20 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:37:25 GMT+08:00 2018
(5)schedule方法不具有追赶执行性
示例:时间37:00:到40:47所对应的task任务被取消了,不执行了,这就是task任务不追赶的情况。
package test.run; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run5 { private static Timer timer = new Timer(); static public class MyTask1 extends TimerTask {
@Override
public void run() {
System.out.println("1 begin 运行了!时间为:" + new Date());
System.out.println("1 end 运行了!时间为:" + new Date());
}
} public static void main(String[] args) {
try {
MyTask1 task1 = new MyTask1();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString1 = "2018-5-7 18:37:00";
Date dateRef1 = sdf1.parse(dateString1);
System.out.println("字符串1时间:" + dateRef1.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
timer.schedule(task1, dateRef1, 5000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串1时间:2018-5-7 18:37:00 当前时间:2018-5-7 18:40:47
1 begin 运行了!时间为:Mon May 07 18:40:47 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:40:47 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:40:52 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:40:52 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:40:57 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:40:57 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:41:02 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:41:02 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:41:07 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:41:07 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 18:41:12 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 18:41:12 GMT+08:00 2018
...
(6)scheduleAtFixedRate方法具有追赶性
示例:从输出结果可以看出,在20:25:43时刻,task1任务执行了很多次之后才按照正常的时间间隔执行,这是由于为了补充两个时间段之间的task1任务,所以就被“补充性”地执行了,这就是Task任务追赶执行的特性。
package test.run; import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask; public class Run6 {
private static Timer timer = new Timer(); static public class MyTask1 extends TimerTask {
@Override
public void run() {
System.out.println("1 begin 运行了!时间为:" + new Date());
System.out.println("1 end 运行了!时间为:" + new Date());
}
} public static void main(String[] args) {
try {
MyTask1 task1 = new MyTask1();
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString1 = "2018-5-7 20:24:00";
Date dateRef1 = sdf1.parse(dateString1);
System.out.println("字符串1时间:" + dateRef1.toLocaleString() + " 当前时间:"
+ new Date().toLocaleString());
timer.scheduleAtFixedRate(task1, dateRef1, 5000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
字符串1时间:2018-5-7 20:24:00 当前时间:2018-5-7 20:25:43
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:43 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:45 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:45 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:50 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:50 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:25:55 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:25:55 GMT+08:00 2018
1 begin 运行了!时间为:Mon May 07 20:26:00 GMT+08:00 2018
1 end 运行了!时间为:Mon May 07 20:26:00 GMT+08:00 2018
...
Java多线程编程(五)定时器Timer的更多相关文章
- java 多线程Thread 子类 定时器Timer
定时器Timer, 定时器分类: 1,指定时间指定任务(明天早上8点准时提醒我起床),相当于linux里面的at命令 2,周期性的执行任务(每隔三分钟闹钟响一次),相当于Linux里面的cron命令 ...
- Java多线程19:定时器Timer
前言 定时/计划功能在Java应用的各个领域都使用得非常多,比方说Web层面,可能一个项目要定时采集话单.定时更新某些缓存.定时清理一批不活跃用户等等.定时计划任务功能在Java中主要使用的就是Tim ...
- Java多线程编程核心技术--定时器
Timer类主要负责计划任务,也就是在指定的时间开始执行某一个任务. 方法schedule(TimerTask task, Date time) public class Task { private ...
- Java多线程编程实战指南(核心篇)读书笔记(五)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76730459冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- 《Java多线程编程核心技术》知识梳理
<Java多线程编程核心技术> @author ergwang https://www.cnblogs.com/ergwang/ 文章末尾附pdf和png下载链接 第1章 Java多线程技 ...
- Java多线程编程核心技术
Java多线程编程核心技术 这本书有利于对Java多线程API的理解,但不容易从中总结规律. JDK文档 1. Thread类 部分源码: public class Thread implements ...
- 《Java 多线程编程核心技术》- 笔记
作为业务开发人员,能够在工作中用到的技术其实不多.虽然平时老是说什么,多线程,并发,注入,攻击!但是在实际工作中,这些东西不见得用得上.因为,我们用的框架已经把这些事做掉了. 比如web开发,外面有大 ...
- Java多线程编程详解
转自:http://programming.iteye.com/blog/158568 线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Ja ...
- Java多线程编程总结(精华)
Java多线程编程总结 2007-05-17 11:21:59 标签:多线程 java 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http ...
- Java多线程编程核心技术(三)多线程通信
线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体.线程间的通信就是成为整体的必用方案之一,可以说,使线程间进行通信后,系统之间的交互性会更强大,在大大提高CPU利用率的同时 ...
随机推荐
- 分库分表(2) --- ShardingSphere(理论)
ShardingSphere---理论 ShardingSphere在中小企业需要分库分表的时候用的会比较多,因为它维护成本低,不需要额外增派人手;而且目前社区也还一直在开发和维护,还算是比较活跃. ...
- 58同城AES签名接口分析
背景:需要获取58同城上面发布的职位信息,其中的包括职位的招聘要求,薪资福利,公司的信息,招聘者的联系方式.(中级爬虫的难度系数) 职位详情页分析 某个职位详情页的链接 https://qy.m.58 ...
- mysql库复制
一.使用navicate复制mysql库 二.使用命令 通过命令:1.创建新数据库CREATE DATABASE `newdb` DEFAULT CHARACTER SET UTF8 COLLATE ...
- IDEA 学习笔记之 1.5已经过时问题
1.5已经过时问题: apache-maven-3.5.0\conf\settings.xml添加: <profile> <id>jdk-1.8</id> < ...
- Scala 学习笔记之集合(5)
import collection.mutable.Buffer object CollectionDemo6 { def main(args: Array[String]): Unit = { // ...
- (八十三)c#Winform自定义控件-导航菜单(扩展)
前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...
- 整理一些大厂的开源平台及github,向他们看齐...
有人苦恼,该如何突破技术的局限性... 有人羡慕,技术上你怎么懂得这么多... 有人哀叹,唉,我已经学不动了... 我的总结(纯属个人想法):身处IT,就得不断学习和积累,才不会被狠狠地甩在身后.什么 ...
- 视频作品《springboot基础篇》上线了
1.场景描述 第一个视频作品出炉了,<springboot基础篇>上线了,有需要的朋友可以直接点击链接观看.(如需购买,请通过本文链接购买) 2. 课程内容 课程地址:https://ed ...
- 超详细的FreeRTOS移植全教程——基于srm32
### 准备 在移植之前,我们首先要获取到FreeRTOS的官方的源码包.这里我们提供两个下载链接: > 一个是官网:http://www.freertos.org/ > 另外一个是代码托 ...
- [ASP.NET Core 3框架揭秘] 依赖注入:控制反转
ASP.NET Core框架建立在一些核心的基础框架之上,这些基础框架包括依赖注入.文件系统.配置选项和诊断日志等.这些框架不仅仅是支撑ASP.NET Core框架的基础,我们在进行应用开发的时候同样 ...