方法一
使用Thread,通过sleep达到定时任务的效果。
package timer;
import java.util.Date;
public class Main {
public static void main(String []args) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println(new Date());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
方法二
使用Timer定时器。在JDK库中Timer类主要负责计划任务的功能,也就是在指定的时间开始某一个任务。Timer类的主要任务就是设置计划任务,但封装任务的类却是TimerTask类。执行计划任务的代码要放到TimerTask的子类中,因为TimerTask是一个抽象类。
Timer中用于定时任务的方法如下所示:
public void schedule(TimerTask task, long delay)
public void schedule(TimerTask task, Date time)
public void schedule(TimerTask task, long delay, long period)
public void schedule(TimerTask task, Date firstTime, long period)
public void scheduleAtFixedRate(TimerTask task, long delay, long period)
public void scheduleAtFixedRate(TimerTask task, Date firstTime,long period)
以上方法具体用法如下所示:
1.public void schedule(TimerTask task, long delay)
该方法的作用是以执行schedule(TimerTask task, long delay)方法当前的时间为参考时间,在此基础上延迟指定的毫秒数后执行一次任务。
package timer;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String []args) {
Timer timer = new Timer();
System.out.println(new Date());
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(new Date());
timer.cancel();
}
}, 5000);
}
}
运行结果
Tue Jun 19 18:50:03 CST 2018
Tue Jun 19 18:50:08 CST 2018
2.public void schedule(TimerTask task, Date time)
在指定的日期执行一次某一任务,如果指定日期早于当前时间,则会立即执行任务。
package timer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String []args) {
try {
Timer timer = new Timer();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2018-6-19 18:59:00";
Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:" + dateRef +",当前时间:" + new Date());
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("任务运行了:,当前时间:" + new Date());
timer.cancel();
}
}, dateRef);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
运行结果
字符串时间:Tue Jun 19 18:59:00 CST 2018,当前时间:Tue Jun 19 18:58:46 CST 2018
任务运行了:,当前时间:Tue Jun 19 18:59:00 CST 2018
3.public void schedule(TimerTask task, long delay, long period)
该方法的作用是以执行schedule(TimerTask task, long delay, long period)方法当前的时间为参考时间,在此基础上延迟指定的毫秒数,再一某一时间间隔无线次数的执行某一任务。
package timer;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String []args) {
Timer timer = new Timer();
System.out.println("当前时间:" + new Date());
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("任务运行了:当前时间:" + new Date());
}
}, 2000, 2000);
}
}
运行结果
当前时间:Tue Jun 19 19:07:55 CST 2018
任务运行了:当前时间:Tue Jun 19 19:07:57 CST 2018
任务运行了:当前时间:Tue Jun 19 19:07:59 CST 2018
任务运行了:当前时间:Tue Jun 19 19:08:01 CST 2018
任务运行了:当前时间:Tue Jun 19 19:08:03 CST 2018
任务运行了:当前时间:Tue Jun 19 19:08:05 CST 2018
任务运行了:当前时间:Tue Jun 19 19:08:07 CST 2018
任务运行了:当前时间:Tue Jun 19 19:08:09 CST 2018
4.public void schedule(TimerTask task, Date firstTime, long period)
该方法的作用是在指定的日期之后,按指定的间隔周期性地无限循环执行某一任务。
(1)计划时间晚于当前时间:任务在未来执行
package timer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String []args) {
try {
Timer timer = new Timer();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2018-6-19 19:14:50";
Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:" + dateRef +",当前时间:" + new Date());
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("任务运行了:,当前时间:" + new Date());
}
}, dateRef, 2000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
运行结果
字符串时间:Tue Jun 19 19:14:50 CST 2018,当前时间:Tue Jun 19 19:14:45 CST 2018
任务运行了:当前时间:Tue Jun 19 19:14:50 CST 2018
任务运行了:当前时间:Tue Jun 19 19:14:52 CST 2018
任务运行了:当前时间:Tue Jun 19 19:14:54 CST 2018
任务运行了:当前时间:Tue Jun 19 19:14:56 CST 2018
(2)计划时间早于当前时间:则立即执行任务。
package timer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String []args) {
try {
Timer timer = new Timer();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2018-6-19 19:14:50";
Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:" + dateRef +",当前时间:" + new Date());
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("任务运行了:,当前时间:" + new Date());
}
}, dateRef, 2000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
运行结果
字符串时间:Tue Jun 19 19:14:50 CST 2018,当前时间:Tue Jun 19 19:16:35 CST 2018
任务运行了:当前时间:Tue Jun 19 19:16:35 CST 2018
任务运行了:当前时间:Tue Jun 19 19:16:37 CST 2018
任务运行了:当前时间:Tue Jun 19 19:16:39 CST 2018
5.public void scheduleAtFixedRate(TimerTask task, long delay, long period)
该方法的作用是以执行scheduleAtFixedRate(TimerTask task, long delay, long period)方法当前的时间为参考时间,在此基础上延迟指定的毫秒数,再一某一时间间隔无线次数的执行某一任务。
package timer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String []args) {
Timer timer = new Timer();
System.out.println("字符串时间,当前时间:" + new Date());
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("任务运行了:当前时间:" + new Date());
}
}, 1000, 1000);
}
}
运行结果
当前时间:Tue Jun 19 19:24:12 CST 2018
任务运行了:当前时间:Tue Jun 19 19:24:13 CST 2018
任务运行了:当前时间:Tue Jun 19 19:24:14 CST 2018
任务运行了:当前时间:Tue Jun 19 19:24:15 CST 2018
6.public void scheduleAtFixedRate(TimerTask task, Date firstTime,long period)
该方法的作用是在指定的日期之后,按指定的间隔周期性地无限循环执行某一任务。为了演示该方法与schedule(TimerTask task, Date firstTime, long period)方法的区别,这里设置任务的开始时间早于当前时间,然后与schedule方法的输出结果对比有什么不同。
package timer;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String []args) {
try {
Timer timer = new Timer();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString = "2018-6-19 19:28:55";
Date dateRef = sdf.parse(dateString);
System.out.println("字符串时间:" + dateRef +",当前时间:" + new Date());
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
System.out.println("任务运行了:,当前时间:" + new Date());
}
}, dateRef, 1000);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
运行结果
字符串时间:Tue Jun 19 19:28:55 CST 2018,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:11 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:12 CST 2018
任务运行了:,当前时间:Tue Jun 19 19:29:13 CST 2018
使用Timer的缺陷:TimerTask是以队列的方式一个一个被执行的,所以执行时间有可能和预期时间不一致,因为前面的任务有可能消耗的时间较长,则后面的任务运行的时间也会被延迟。我们来看一个例子:
package timer;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
public class Main {
public static void main(String []args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("任务(1)运行了:,当前时间:" + new Date());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 1000);
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("任务(2)运行了:,当前时间:" + new Date());
}
}, 1000);
}
}
运行结果
任务(1)运行了:,当前时间:Tue Jun 19 19:37:02 CST 2018
任务(2)运行了:,当前时间:Tue Jun 19 19:37:07 CST 2018
有打印结果可知,任务(2)是在任务(1)执行结束后才开始执行的。为了任务(1)与任务(2)同时进行,我们可以使用ScheduledExecutorService来解决这个问题。
方法三:ScheduledExecutorService
第二个参数:首次执行要延迟的时间
第三个参数:任务执行间隔
第四个参数:间隔时间单位
package timer;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String []args) {
ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
System.out.println("当前时间:" + new Date());
service.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
System.out.println("任务(1)运行了,当前时间:" + new Date());
}
}, 1, 3, TimeUnit.SECONDS);
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("任务(2)运行了,当前时间:" + new Date());
}
}, 1, 3, TimeUnit.SECONDS);
}
}
运行结果
由打印结果可知,任务(1)和任务(2)是同时运行的。
当前时间:Tue Jun 19 20:07:27 CST 2018
任务(1)运行了,当前时间:Tue Jun 19 20:07:28 CST 2018
任务(2)运行了,当前时间:Tue Jun 19 20:07:28 CST 2018
任务(2)运行了,当前时间:Tue Jun 19 20:07:31 CST 2018
任务(1)运行了,当前时间:Tue Jun 19 20:07:31 CST 2018
任务(2)运行了,当前时间:Tue Jun 19 20:07:34 CST 2018
任务(1)运行了,当前时间:Tue Jun 19 20:07:34 CST 2018
任务(2)运行了,当前时间:Tue Jun 19 20:07:37 CST 2018
任务(1)运行了,当前时间:Tue Jun 19 20:07:37 CST 2018
任务(2)运行了,当前时间:Tue Jun 19 20:07:40 CST 2018
任务(1)运行了,当前时间:Tue Jun 19 20:07:40 CST 2018