标签:
定时任务是我们经常遇到的业务场景,我们有很多的功能都需要这样的技术来实现,例如:定时获取一些数据push出去,定时处理一些清理任务,定时检查某个值等。那么我们该怎么实现,在实现中又该注意一些什么?
定时任务就是另开一个线程来执行,其实也是并发的一类,大家可能不好理解,说定时不就是到时间执行一下,怎么还会产生并发,这里主要是看两个指标,一是看执行频率,二是看每次执行的时间,如果执行频率高并且执行任务又会很耗时,那么这时候就形成了并发,当然还有一种情况那就是,定时的job中调用其它服务的方法,而正常的业务逻辑中也调用那个服务的方法,那么这时在某个巧合的时间也有可能发生并发。
所以我们在写定时任务的时候也要注意这么两点:
1:如果执行频率高并且执行任务又会很耗时,要在job的执行方法上加同步处理。
2:如果job里调用其它服务方法,那么其它服务所提供的方法也要保证发布成线程安全的方法。
下面我们来说一下有几种实现定时任务的方法:
1:java提供的timer
package com.home.thread.thread10; import java.util.Date; import java.util.Timer; /** * @author gaoxu * 实践出真知! */ public class TimerMain { /** * @param args */ public static void main(String[] args) { Timer timer = new Timer(); timer.schedule(new TimerTaskThread(), new Date(), 2000); } }
package com.home.thread.thread10; import java.util.Date; import java.util.TimerTask; /** * @author gaoxu * 实践出真知! */ public class TimerTaskThread extends TimerTask{ //没有参数的构造函数 public TimerTaskThread(){ } //也可以写有参数的构造函数 @Override public synchronized void run() { System.out.println(new Date().toString()+"Timer方式,我是两秒执行一次"); //这里可以写自己要实现的定时业务 } }
这是一个由timer来实现的定时任务,运行结果如下:
Sat Feb 07 01:25:31 CST 2015,Timer方式,我是两秒执行一次 Sat Feb 07 01:25:33 CST 2015,Timer方式,我是两秒执行一次 Sat Feb 07 01:25:35 CST 2015,Timer方式,我是两秒执行一次 Sat Feb 07 01:25:37 CST 2015,Timer方式,我是两秒执行一次
2:由开源框架Quartz实现的定时任务
package com.home.thread.thread10; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SchedulerFactory; import org.quartz.impl.StdSchedulerFactory; import com.home.JobServiceImpl; /** * @author gaoxu * 实践出真知! */ public class SchedulerMain { public static void main(String[] para) { try { SchedulerFactory sf = new StdSchedulerFactory(); Scheduler scheduler = sf.getScheduler(); JobServiceImpl jobService = new JobServiceImpl(); jobService.setScheduler(scheduler); jobService.platDataCollectInterval(2); } catch (SchedulerException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package com.home; import org.quartz.JobBuilder; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.SimpleScheduleBuilder; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import com.home.job.TestJob; /** * @author gaoxu * 实践出真知! */ public class JobServiceImpl { private Scheduler scheduler; public void setScheduler(Scheduler scheduler) { this.scheduler = scheduler; } public Scheduler getScheduler() { return scheduler; } public void platDataCollectInterval(int interval) throws SchedulerException, Exception { System.out.println("update PlatDataCollect cycle start"); JobDetail jobDetail = JobBuilder.newJob(TestJob.class).withIdentity("testJob_1", "group_1").build(); Trigger trigger = TriggerBuilder .newTrigger() .withIdentity("trigger_1", "group_1") .withSchedule( SimpleScheduleBuilder .repeatSecondlyForever(interval)).build(); scheduler.scheduleJob(jobDetail, trigger); scheduler.start(); } }
package com.home.job; import java.util.Date; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class TestJob implements Job{ @Override public void execute(JobExecutionContext arg0) throws JobExecutionException { System.out.println("test job date:" + new Date().toString()); } }
这里有三个类,其中job类是任务的执行者,Scheduler是一个调度器,调度器中可以创建多个Trigger,每个Trigger可以执行一个job。
log4j:WARN No appenders could be found for logger (org.quartz.impl.StdSchedulerFactory). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. update PlatDataCollect cycle start test job date:Sat Feb 07 01:30:31 CST 2015 test job date:Sat Feb 07 01:30:33 CST 2015 test job date:Sat Feb 07 01:30:35 CST 2015 test job date:Sat Feb 07 01:30:37 CST 2015
3:是线程来实现
package com.home.thread.thread10; /** * @author gaoxu * 实践出真知! */ public class ThreadMain { public static void main(String[] para) { ThreadTask threadTask = new ThreadTask(); threadTask.start(); } }
package com.home.thread.thread10; import java.util.Date; public class ThreadTask extends Thread{ public void run(){ while(true){ try { Thread.sleep(2000); System.out.println(new Date().toString()+"线程方式,我是两秒执行一次"); //这里可以写自己要实现的定时业务 } catch (InterruptedException e) { e.printStackTrace(); } } } }
运行结果:
Sat Feb 07 01:33:34 CST 2015线程方式,我是两秒执行一次 Sat Feb 07 01:33:36 CST 2015线程方式,我是两秒执行一次 Sat Feb 07 01:33:38 CST 2015线程方式,我是两秒执行一次 Sat Feb 07 01:33:40 CST 2015线程方式,我是两秒执行一次 Sat Feb 07 01:33:42 CST 2015线程方式,我是两秒执行一次
还有很多方式可以实现工作任务,例如java.util.concurrent.ScheduledThreadPoolExecutor,这里就不在举例。
一定要注意定时任务的并发性,避免发生并发错误。
标签:
原文地址:http://blog.csdn.net/andy_gx/article/details/43588001