一. 为什么要出现定时任务?
在实际生活和开发中,常常会遇到类似的情况, 如 1.女朋友生日那一天,发送定时消息,提醒生日快乐 2. 给某人写邮件编写好内容之后,在晚上10点时准时发送, 3 某天固定8点起床,晚上10点睡觉 4.母亲节,父亲节时给父母发送消息。 等生活中的定时小例子 (闹钟,备忘录都属于定时)。
开发中,1. 给已经注册的用户,在用户生日那天,发送生日祝福. 2. 公司员工,当入职满一年时,增加年假至5天,入职5年时,增加年假至10天。 3.定时删除三个月前的日志记录消息。 4. 定时监测网站访问情况等开发中的定时小例子。
这些生活和开发实例,都属于定时任务。 定时任务,是很常见的,也是很重要的。
JavaSE 阶段提供了 三种方式,来实现定时任务。
JavaEE 阶段,使用 Quartz 框架来实现定时任务。
二. JavaSE 阶段实现定时任务
二.一 多线程 Runnable 和Thread 实现定时任务
import java.text.SimpleDateFormat; import java.util.Date; /** * * Thread 多线程通过休眠时间来实现定时执行 * @author 两个蝴蝶飞 * */ public class ThreadDemo { public static void main(String []args){ //定时的时间 Long SLEEP_TIME=1000*5L; Runnable runnable=new Runnable() { @Override public void run() { while(true){ try { //通过设置休眠,来达到定时的效果。 每5s执行一次 Thread.sleep(SLEEP_TIME); SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String localeDate=sdf.format(new Date()); System.out.println("Thread 线程:当前时间为:"+localeDate); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } }; Thread thread=new Thread(runnable); thread.start(); } }
控制台打印输出:
如果想取消定时的话, 可以定义一个全局常量flag,flag默认是true, 将 while(true) 改成 while(flag), 当取消定时时,将flag 由true 改成false 即可。
二.二 TimerTask 和 Timer 实现定时任务
二.二.一 代码编写
import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; import java.util.TimerTask; /** * * TimerTask 和Timer 实现定时任务 * @author 两个蝴蝶飞 * */ public class TaskDemo { public static void main(String[] args) { Timer timer=new Timer(); TimerTask task=new TimerTask() { @Override public void run() { SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String localeDate=sdf.format(new Date()); System.out.println("Task任务:当前时间为:"+localeDate); } }; timer.scheduleAtFixedRate(task,0,5000); //调用 cancel()方法来取消定时 //timer.cancel(); } }
通过调用 Timer 对象的 scheduleAtFixedRate() 方法,来实现定时任务。
控制台打印输出:
二.二.二 Timer中的调度方法
task 均为执行定时任务的对象,时间单位为 ms.
二.三 ScheduledExecutor 实现定时任务
在 java.util.concurrent 包下
import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * ScheduledExecutor 实现定时调度 * @author 两个蝴蝶飞 * */ public class ScheduleDemo { public static void main(String[] args) { //定义定时任务 Runnable runnable=new Runnable() { @Override public void run() { SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String localeDate=sdf.format(new Date()); System.out.println("Scheduled调度:当前时间为:"+localeDate); } }; //定义调度服务 ScheduledExecutorService scheduledExecutorService=Executors.newSingleThreadScheduledExecutor(); //运行, 哪个任务,开始时间,间隔时间,间隔单位 scheduledExecutorService.scheduleAtFixedRate(runnable, 0, 2, TimeUnit.SECONDS); } }
控制台打印输出:
三. JavaSE 实现调度的不足
上面的三种方式,虽然都实现了定时任务,但面对复杂多变的定时任务情况,就显得力不从心了。
如,
- 无法实现类似 ‘每年的母亲节给母亲发送祝福’,‘每个月的最后一天显示员工的本月的工作情况’,‘距离每个月10号最近的工作日发薪资’ 等非固定日期的情况。开发者不能在程序中进行判断日期。
- 无法与当前主流框架 Spring 进行很好的整合。
- 定时任务的事务处理,需要开发者自己进行处理。
- 定时任务持久化保存
想处理好定时任务,可以学习一下 Quartz 定时任务框架。
谢谢您的观看!!!