java 内置定时器实现定时任务和自定义定时任务

来源:互联网 发布:seo外包公司 小周 编辑:程序博客网 时间:2024/04/29 12:13

首先,如果要执行一些简单的定时器任务,无须做复杂的控制,也无须保存状态,那么可以考虑使用JDK 入门级的定期器Timer来执行重复任务。

JDK中,定时器任务的执行需要两个基本的类:
    java.util.Timer;
    java.util.TimerTask;

要运行一个定时任务,最基本的步骤如下:
1、建立一个要执行的任务TimerTask,TimerTask是一个抽象类,由 Timer 安排为一次执行或重复执行的任务。它有一个抽象方法run()----计时器任务要执行的操作。因此,每个具体的任务类都必须继承TimerTask类,并且重写run()方法。
2、创建一个Timer实例,通过Timer提供的schedule()方法,将 TimerTask加入到定时器Timer中,同时设置执行的规则即可。
 
当程序执行了Timer初始化代码后,Timer定时任务就会按照设置去执行。
 
Timer中的schedule()方法是有多种重载格式的,以适应不同的情况。该方法的格式如下:
 void schedule(TimerTask task, Date time)
          安排在指定的时间执行指定的任务。
 void schedule(TimerTask task, Date firstTime, long period)
          安排指定的任务在指定的时间开始进行重复的固定延迟执行。
 void schedule(TimerTask task, long delay)
          安排在指定延迟后执行指定的任务。
 void schedule(TimerTask task, long delay, long period)
          安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。

import java.util.Scanner;import java.util.Timer;import java.util.TimerTask;public class TimerTest {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new MyTask(), 1000, 2000);// 在1秒后执行此任务,每次间隔2秒,如果传递一个Data参数,就可以在某个固定的时间执行这个任务.Scanner sc = new Scanner(System.in);System.out.println("输入任何字符串停止任务:" + sc.next());timer.cancel();}/** * 定时任务实体 * @author Administrator * */static class MyTask extends TimerTask {@Overridepublic void run() {System.out.println("run");}}}

下面给出一个复杂点的例子,其中告诉大家怎么退出单个TimerTask,怎么退出所有Task

import java.util.Scanner;import java.util.Timer;import java.util.TimerTask;public class TimerTest1 {public static void main(String[] args) {Timer timer = new Timer();MyTask myTask1 = new MyTask();myTask1.setInfo("task-1");MyTask myTask2 = new MyTask();myTask2.setInfo("task-2");timer.schedule(myTask1, 1000, 2000);timer.scheduleAtFixedRate(myTask2, 2000, 3000);while (true) {try {Scanner sc = new Scanner(System.in);String state = sc.next();//当接收到的字符串时  cancel_1  时,停止  myTask1 任务if(state.equals("cancel_1")){myTask1.cancel();}//当接收到的字符串时  cancel_2  时,停止  myTask2 任务else if(state.equals("cancel_2")){myTask2.cancel();//当接收到的字符串时  cancel_all  时,停止  所有任务}else if(state.equals("cancel_all")){timer.cancel();break;}//当接受到开头是  task_1 的字符串,替换 myTask1实体if(state.startsWith("task_1")){myTask1.setInfo(state);//当接受到开头是  task_1 的字符串,替换 myTask2实体}else if(state.startsWith("task_2")){myTask2.setInfo(state);}} catch (Exception e) {e.printStackTrace();}}}/** * 定时任务实体 * @author Administrator * */static class MyTask extends TimerTask {String info = "";public void run() {System.out.println(info);}public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}}}

但是我们在应用场景中会遇到每一个任务的执行时间都不相同,并且每一个任务只执行一次,如果按照上面的做法,就是每次生成一个TimerTask放到Timer中执行,这样太耗费资源了,我们需要实现一个线程来监听所有的任务。

public class TimerTest2 extends Thread {private static long TIME_OUT = 10000;// 每一个任务在定时器中的超时时间// 任务列表,线程安全private static List<MyTask> myTasks = Collections.synchronizedList(new ArrayList<MyTask>());public void run() {while (true) {// 同步synchronized (myTasks) {if (myTasks.size() > 0) {MyTask myTask = myTasks.get(0);long flagTime = TIME_OUT- (new Date().getTime() - myTask.getDate().getTime());// 获取第一个任务,并且判断该任务是否超时,如果是,删除该任务if (flagTime < 0) {myTasks.remove(myTask);} else {try {// 如果该任务没有超时,继续等待时间myTasks.wait(flagTime);} catch (InterruptedException e) {e.printStackTrace();}}} else {try {myTasks.wait();// 如果列表为空,那么就一直休眠} catch (InterruptedException e) {e.printStackTrace();}}}}}/** * 添加新的任务 *  * @param info */public void addTask(String info) {// 创建新的任务MyTask myTask = new MyTask();myTask.setDate(new Date());myTask.setInfo(info);// 同步synchronized (myTasks) {// 将任务添加到任务列表中,并且唤醒线程myTasks.add(myTask);myTasks.notify();}}/** * 检查该任务是否存在 * @param info * @return */public boolean checkTask(String info) {synchronized (myTasks) {//遍历任务列表,判断该任务是否存在for (MyTask myTask : myTasks) {if (myTask.getInfo().equals(info)) {return true;}}return false;}}public static void main(String[] args) {TimerTest2 timerTest2 = new TimerTest2();timerTest2.start();//启动线程timerTest2.addTask("task");try {Thread.sleep(5000);System.out.println("当前过了5秒,任务  task 是否存在 :" + timerTest2.checkTask("task"));Thread.sleep(6000);System.out.println("当前过了11秒,任务  task 是否存在 :" + timerTest2.checkTask("task"));} catch (InterruptedException e) {e.printStackTrace();}}/** * 任务实体类 * @author Administrator * */static class MyTask {String info;Date date;//任务实体生成时间public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}public Date getDate() {return date;}public void setDate(Date date) {this.date = date;}}}

从以上程序可以看出,每个任务(MyTask) 都放置了一个date(生成实体对象的时间),然后设置每一个任务的超时时间为10秒。任务是以链表的形式存放的,在run方法中,当任务链表中没有任务时,永久休眠,添加新的任务时,唤醒线程,线程中判断该任务是否超时,如果不超时计算出超时时间,并且休眠,如果超时,则删除该任务。

以上程序可以继续扩展,可以将超时时间放到任务实体中,做到完全控制任务的运行时间


1 0