java中的定时任务, 使用java实现有3种方式:
1, 使用普通thread实现
@Test public void test1() { // 单位: 毫秒 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实现: 可控制启动或取消任务, 可指定第一次执行的延迟
线程安全, 但只会单线程执行, 如果执行时间过长, 就错过下次任务了, 抛出异常时, timerWork会终止
@Test public void test2 () { TimerTask task = new TimerTask() { @Override public void run() { System.out.println("Hello !!!"); } }; Timer timer = new Timer(); long delay = 0; long intevalPeriod = 1 * 1000; // schedules the task to be run in an interval timer.scheduleAtFixedRate(task, delay, intevalPeriod); }
3, 使用 ScheduledExcecutorService 实现
ScheduledExecutorService 是java.util.concurrent种的额一个累, 用于实现定时任务
它可以: 1, 通过线程池的方式执行任务
2, 设定第一次的延迟事件
3, 提供良好的约定, 设定时间间隔
@Test public void test() { Runnable runnable = new Runnable() { public void run() { System.out.println("Hello !!"); } }; ScheduledExecutorService service = Executors .newSingleThreadScheduledExecutor(); // 第二个参数为首次执行的延时时间,第三个参数为定时执行的间隔时间 service.scheduleAtFixedRate(runnable, 10, 1, TimeUnit.SECONDS); }
4, 使用spring的 spring-task 实现
第一种方式, 注解的方式实现
@Target({java.lang.annotation.ElementType.METHOD, java.lang.annotation.ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Scheduled { public abstract String cron(); public abstract long fixedDelay(); public abstract long fixedRate(); }
fixedDelay: 设定间隔时间为 5000ms fixedRate: 设定固定速率, 以固定速率5s来执行 cron="0 0 2 * * ? ": 使用时间表达式
第二种方式, 配置文件配置的方式实现
<task:scheduled-tasks> <task:scheduled ref="taskJob" method="job1" cron="0 * * * * ?"/> </task:scheduled-tasks> /* taskJob 为执行任务类, job1 为执行的函数*/ <context:component-scan base-package="com.wenbronk.mytask " />
2, 添加配置信息
<!—开启这个配置,spring才能识别@Scheduled注解 --> <task:annotation-driven scheduler="qbScheduler" mode="proxy"/> <task:scheduler id="qbScheduler" pool-size="10"/>
3, 代码实现
@Scheduled(fixedDelay = 5000) public void doSomething() { // something that should execute periodically }
时间表达式
一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素。 按顺序依次为 秒(0~59) 分钟(0~59) 小时(0~23) 天(月)(0~31,但是你需要考虑你月的天数) 月(0~11) 天(星期)(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT) 年份(1970-2099)
常用的表达式为:
0 0 10,14,16 * * ? 每天上午10点,下午2点,4点 0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时 0 0 12 ? * WED 表示每个星期三中午12点 "0 0 12 * * ?" 每天中午12点触发 "0 15 10 ? * *" 每天上午10:15触发 "0 15 10 * * ?" 每天上午10:15触发 "0 15 10 * * ? *" 每天上午10:15触发 "0 15 10 * * ? 2005" 2005年的每天上午10:15触发 "0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发 "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发 "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 "0 0-5 14 * * ?" 在每天下午2点到下午2:05期间的每1分钟触发 "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发 "0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发 "0 15 10 15 * ?" 每月15日上午10:15触发 "0 15 10 L * ?" 每月最后一日的上午10:15触发 "0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发 "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最后一个星期五上午10:15触发 "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发
5, 使用 第三方插件 Quartz实现
maven依赖
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency>
5. 1) 可以设置一个类, 继承自 QuartzJobBean
1, 配置文件:
<!-- 配置作业类 --> <bean name="job1" class="org.springframework.scheduling.quartz.JobDetailBean"> <property name="jobClass" value="com.gy.Job1" /> <property name="jobDataAsMap"> <map> <entry key="timeout" value="0" /> </map> </property> </bean> <!-- 配置触发方式 --> <!-- simpleTrggerBean 只支持一种方式调度 --> <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="job1" /> <property name="startDelay" value="0" /> <!-- 调度工厂实例化后,经过0秒开始执行调度 --> <property name="repeatInterval" value="2000" /> <!-- 每2秒调度一次 --> </bean> <!-- 使用CronTrggerBean , 支持时间表达式 --> <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="job1" /> <!-- 每天12点运行一次 --> <property name="cronExpression" value="0 0 12 * * ?" /> </bean>
2, 配置调度工厂:
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger" /> </list> </property> </bean>
3, 定义作业类:
public class Job1 extends QuartzJobBean { private int timeout; private static int i = 0; // 调度工厂实例化后,经过timeout时间开始执行调度 public void setTimeout(int timeout) { this.timeout = timeout; } /** * 要调度的具体任务 */ @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { System.out.println("定时任务执行中…"); } }
5.2) 直接写一个普通类, 在配置中进行配置
任务类:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.StringRedisTemplate; /** * 定时删除用户收听过的poi * @author wenbronk * @time 2017年3月28日 下午2:01:09 2017 */ public class DelListenerPOIScheduler { @Autowired private StringRedisTemplate redisTemplate; public void doCheck() { System.out.println("定时任务执行了...."); } }
配置文件:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd"> <!-- 配置作业类 --> <bean id="delRedisListenerHistory" class="com.iwhere.easy.travel.valid.DelListenerPOIScheduler" /> <!-- 作业类描述, 使用方法调度 --> <bean id="methodInvoking" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="delRedisListenerHistory" /> <property name="targetMethod" value="doCheck" /> </bean> <!-- 触发器, 使用定时触发 --> <bean id="delTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="jobDetail" ref="methodInvoking" /> <property name="cronExpression" value="0/10 * * * * ?" /> </bean> <!-- 总调度器 --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="delTrigger" /> </list> </property> </bean> </beans>
6, 在springboot中实现定时任务:
package com.iwhere.base.scheduling; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; /** * 整合定时任务 * EnableScheduling 实现spring中的task功能 * @Scheduled中配置时间表达式 * @author 231 * */ @Configuration // 相当于配置beans, @EnableScheduling // <task:*>, 让spring进行任务调度 public class SchedulingConfig { @Scheduled(cron="0/20 * * * * ?") // 20秒执行一次 public void scheduler() { System.out.println("定时任务执行了"); } }
7, Springboot 集成 quartz
为什么非要集成呢, 因为quartz支持集群定时任务, 现在还用不到, 防止以后用到
1, 配置quartz的配置信息类
package com.iwhere.easy.travel.timeschedule; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean; import org.springframework.scheduling.quartz.SchedulerFactoryBean; /** * quartz的配置信息 * @author wenbronk * @time 2017年3月29日 下午5:20:29 2017 */ @Configuration public class TimeScheduleConfig { @Bean(name = "detailFactoryBean") public MethodInvokingJobDetailFactoryBean detailFactoryBean(DelListenerPOIScheduler scheduledTasks) { MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean(); // 这儿设置对应的Job对象 bean.setTargetObject(scheduledTasks); // 这儿设置对应的方法名 与执行具体任务调度类中的方法名对应 bean.setTargetMethod("doCheck"); bean.setConcurrent(false); return bean; } @Bean(name = "cronTriggerBean") public CronTriggerFactoryBean cronTriggerBean(MethodInvokingJobDetailFactoryBean detailFactoryBean) { CronTriggerFactoryBean trigger = new CronTriggerFactoryBean(); trigger.setJobDetail(detailFactoryBean.getObject()); try { trigger.setCronExpression("0 0 1 * * ?");// 每天1点执行一次 } catch (Exception e) { e.printStackTrace(); } return trigger; } @Bean public SchedulerFactoryBean schedulerFactory(CronTriggerFactoryBean cronTriggerBean) { SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean(); schedulerFactory.setTriggers(cronTriggerBean.getObject()); return schedulerFactory; } }
2), 具体的作业类
package com.iwhere.easy.travel.timeschedule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Configurable; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.stereotype.Component; /** * 定时删除用户收听过的poi * @author wenbronk * @time 2017年3月28日 下午2:01:09 2017 */ @Component @Configurable @EnableScheduling public class DelListenerPOIScheduler { private Logger LOGGER = LoggerFactory.getLogger(DelListenerPOIScheduler.class); @Autowired private StringRedisTemplate redisTemplate; public void doCheck() { try { String key = "noteUserListenedPoi:*"; redisTemplate.delete(key); LOGGER.info("redis中用户收听历史被清空"); } catch (Exception e) { e.printStackTrace(); LOGGER.error("redis删除用户收听记录失败"); } } }