Java 定时任务系列(1)- Java原生支持

发布时间:2019-11-17 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Java 定时任务系列(1)- Java原生支持脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

1、普通thread实现

这是最常见的,创建一个thread,然后让它在while循环里一直运行着,通过sleep方法来达到定时任务的效果。这样可以快速简单的实现,代码如下:

public class Task1 { public static void main(String[] args) {   // run in a second   final long timeinterval = 1000;   Runnable runnable = new Runnable() {   public void run() {     while (true) {       // ------- code for task to run       System.out.PRintln("Hello !!");       // ------- ends here       try {        Thread.sleep(timeInterval);       } catch (InterruptedException e) {         e.printStackTrace();       }       }     }   };   Thread thread = new Thread(runnable);   thread.start();   } } 

2、用Timer和TimerTask

介绍
java.util.Timer定时器,实际上是个线程,定时调度所拥有的TimerTasks。
一个java.util.TimerTask实际上就是一个拥有run方法的类,需要定时执行的代码放到run方法体内,TimerTask一般是以匿名类的方式创建。
上面的实现是非常快速简便的,但它也缺少一些功能。
用Timer和TimerTask的话与上述方法相比有如下好处:
当启动和去取消任务时可以控制
第一次执行任务时可以指定你想要的delay时间
在实现时,Timer类可以调度任务,TimerTask则是通过在run()方法里实现具体任务。
Timer实例可以调度多任务,它是线程安全的。
当Timer的构造器被调用时,它创建了一个线程,这个线程可以用来调度任务。

下面是代码:
Timer 测试类代码:

//import java.util.Date; import java.util.Timer;  //import com.baibutao.apps.linkshop.uxiang.server.util.DateUtil;   public class testTimerTask {          public static void main(String[] args){             TaskA taskA = new TaskA();             Timer timer = new Timer();             timer.schedule(taskA, 5 * 1000, 5 * 1000);              //Date date = DateUtil.parse("2014-12-04 16:50:00");             //timer.schedule(taskA, date , 5 * 1000);             //timer.scheduleAtFixedRate(taskA, date, 5 * 1000);         }     } 

任务类代码:

import java.util.Date; import java.util.TimerTask;  import wint.lang.utils.DateUtil;  // 定义一个任务类 public class TaskA extends TimerTask{      @override     public void run() {         System.out.println(DateUtil.formatFullDate(new Date()));     }  } 

关于Timer类的调用方法:
void java.util.Timer.schedule(TimerTask task, long delay):多长时间(毫秒)后执行任务

void java.util.Timer.schedule(TimerTask task, Date time):设定某个时间执行任务

void java.util.Timer.schedule(TimerTask task, long delay, long PEriod):delay时间后开始执行任务,并每隔period时间调用任务一次。

void java.util.Timer.schedule(TimerTask task, Date FirstTime, long period):第一次在指定firstTime时间点执行任务,之后每隔period时间调用任务一次。

void java.util.Timer.scheduleAtFixedRate(TimerTask task, long delay, long period):delay时间后开始执行任务,并每隔period时间调用任务一次。

void java.util.Timer.scheduleAtFixedRate(TimerTask task, long delay, long period):第一次在指定firstTime时间点执行任务,之后每隔period时间调用任务一次。

void java.util.Timer.cancel():终止该Timer

boolean java.util.TimerTask.cancel():终止该TimerTask

可以为每个Timer指定多个TimerTask

虽然可通过void java.util.Timer.schedule(TimerTask task, Date firstTime, long period)方法完成“例如:每天上午10点执行一次”的业务,但该实现是基于进行一天(1000 * 60 * 60 * 24毫秒)进行延迟的机制实现的,并不是指定某个具体时间进行执行的。

对于该种需求,可通过Quartz来进行实现

方法名称schedule()和scheduleAtFixedRate()两者的区别
当需要根据period区间时间循环多次调用任务的时候,会存在两种不同的策略,两种方法提供了不同的策略。
调用方法(1)、(2)只是单次执行,不存在多次调用任务的情况,所以没有提供scheduleAtFixedRate方法的调用方式。
schedule()方法更注重保持间隔时间的稳定:保障每隔period时间可调用一次
scheduleAtFixedRate()方法更注重保持执行频率的稳定:保障多次调用的频率趋近于period时间,如果某一次调用时间大于period,下一次就会尽量小于period,以保障频率接近于period
进一步的说明参见eg366的博客,星星的技专栏

3、ScheduledExecutorService

ScheduledExecutorService是从Java SE 5的java.util.concurrent里,做为并发工具类被引进的,这是最理想的定时任务实现方式。
相比于上两个方法,它有以下好处:

相比于Timer的单线程,它是通过线程池的方式来执行任务的
可以很灵活的去设定第一次执行任务delay时间
提供了良好的约定,以便设定执行的时间间隔

下面是实现代码,我们通过ScheduledExecutorService#scheduleAtFixedRate展示这个例子,通过代码里参数的控制,首次执行加了delay时间。

import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnIT; public class Task3 {   public static void main(String[] args) {     Runnable runnable = new Runnable() {       public void run() {         // task to run goes here         System.out.println("Hello !!");       }     };     ScheduledExecutorService service = Executors                     .newSingleThreadScheduledExecutor();     service.scheduleAtFixedRate(runnable, 0, 1, TimeUnit.SECONDS);   } } 

关于ScheduledExecutorService 和 Timer的优劣,Timer没有很好的错误处理机制,请参考苦行僧的博客
关于ScheduledExecutorService 的具体用法,请参照涛涛的博客

4、web容器中利用ServletContextListener实现定时任务

一个实现ServletContextListener接口的类: StatisticsContextListener.java:

package com.ed.cnc.servletListener;  import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener;  import com.ed.cnc.city.StatisticsTask;  /**  * 统计ContextListener  * @author westd  *  */ /**  * @author westd  *  */ public class StatisticsContextListener implements ServletContextListener {      private java.util.Timer timer = null;       /**      * 这个方法在Web应用服务做好接受请求的时候被调用。      *       * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent)      */     public void contextInitialized(ServletContextEvent event)      {         timer = new java.util.Timer(true);         event.getServletContext().LOG("定时器已启动");          timer.schedule(new StatisticsTask(event.getServletContext()), 0, 60*60*1000);//每隔1小时         event.getServletContext().log("已经添加任务调度表");     }       /**      * 这个方法在Web应用服务被移除,没有能力再接受请求的时候被调用。      *       * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent)      */     public void contextDestroyed(ServletContextEvent event)     {         timer.cancel();         event.getServletContext().log("定时器销毁");     }  } 

一个继承于TimerTask的一个类:StatisticsTask.java

package com.ed.cnc.city;  import java.util.Calendar; import java.util.TimerTask;  import javax.servlet.ServletContext;   /**  * 统计任务  * @author westd  *  */ public class StatisticsTask extends TimerTask {      private static final int STATISTICS_SCHEDULE_HOUR = 0;     private static boolean isRunning = false;     private ServletContext context = null;      public StatisticsTask(ServletContext context)     {         this.context = context;     }      @Override     public void run()     {         Calendar cal = Calendar.getInstance();          //System.out.println(isRunning);         if (!isRunning)          {              if (STATISTICS_SCHEDULE_HOUR == cal.get(Calendar.HOUR_OF_DAY)) //查看是否为凌晨             {                  isRunning = true;                  context.log("开始执行指定任务");                  //TODO 添加自定义的详细任务                 executeTask();                  //指定任务执行结束                 isRunning = false;                 context.log("指定任务执行结束");              }          }          else          {             context.log("上一次任务执行还未结束");         }      } /**  * 执行任务  */ public void executeTask() {     System.out.println("任务1");     System.out.println("任务2"); } 

}
web.XMl中添加如下代码:

<listener>         <listener-class>com.ed.cnc.servletListener.StatisticsContextListener</listener-class> </listener> 

脚本宝典总结

以上是脚本宝典为你收集整理的Java 定时任务系列(1)- Java原生支持全部内容,希望文章能够帮你解决Java 定时任务系列(1)- Java原生支持所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。