一、最原始的定时任务
1.采用线程方式
public static void runTask(){
final long timeInterval = 1000;
Runnable runnable = new Runnable() {
public void run() {
while (true){
System.out.println("hello");
try {
Thread.sleep(timeInterval);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
};
Thread thread = new Thread(runnable);
thread.start();
}
二、采用jdk中的Timer类
package com.flx.timer;
import com.flx.timer.task.SimpleTask;
import com.flx.timer.task.SimpleTaskLiving;
import com.flx.util.BaseFunction;
import com.flx.util.date.CalendarUtils;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* Created by Fenglixiong on 2017/9/25.
*/
public class TimerHome {
private static Timer timer = new Timer();
public static void main(String[] args) {
TaskOne(10);
TaskTwo(CalendarUtils.addSeconds(new Date(),10));
TaskThree(CalendarUtils.addSeconds(new Date(),10));
TaskFour();
TaskFive(CalendarUtils.addSeconds(new Date(),10));
TaskSix();
TimerTaskPool();
TimerTask01();
TimerTask02();
}
/**
* 指定延迟时间执行定时任务
* @param time
*/
public static void TaskOne(int time){
BaseFunction.console("准备执行任务TaskOne...");
Timer timer = new Timer();
timer.schedule(new SimpleTask(),time*1000);
}
/**
* 在指定时间执行任务
* @param date
*/
public static void TaskTwo(Date date){
BaseFunction.console("准备执行任务TaskTwo...");
CalendarUtils.sayTime(new Date());
Timer timer = new Timer();
timer.schedule(new SimpleTask(),date);
}
/**
* 在指定时间执行然后以指定时间间隔执行任务
* @param date
*/
public static void TaskThree(Date date){
BaseFunction.console("准备执行任务TaskThree...");
CalendarUtils.sayTime(new Date());
Timer timer = new Timer();
timer.schedule(new SimpleTaskLiving("TaskThree"),date,3000);
}
/**
* 在指定时间延迟之后执行然后以指定时间间隔执行任务
*
*/
public static void TaskFour(){
BaseFunction.console("准备执行任务TaskFour...");
CalendarUtils.sayTime(new Date());
Timer timer = new Timer();
timer.schedule(new SimpleTaskLiving("TaskFour"),5000,3000);
}
/**
* 在指定时间延迟之后执行然后以指定时间间隔执行任务
*
*/
public static void TaskFive(Date firstTime){
BaseFunction.console("准备执行任务TaskFive...");
CalendarUtils.sayTime(new Date());
Timer timer = new Timer("TaskFive");
timer.scheduleAtFixedRate(new SimpleTaskLiving(),firstTime,3000);
}
/**
* 在指定时间延迟之后执行然后以指定时间间隔执行任务
*
*/
public static void TaskSix(){
BaseFunction.console("准备执行任务TaskSix...");
CalendarUtils.sayTime(new Date());
Timer timer = new Timer();
timer.scheduleAtFixedRate(new SimpleTaskLiving("TaskSix"),20000,3000);
}
/**
* TimerTask01();
* TimerTask02();
* 同时执行这两个task
* 1.如果是两个Timer的话相当于两个线程互相不会影响
* 2.如果是一个Timer的话计划执行两个定时任务的话
* 其中一个延迟或者阻塞会影响另一个任务的执行
*/
public static void TimerTask01(){
CalendarUtils.sayTime(new Date());
timer.schedule(new TimerTask() {
public void run() {
System.out.println("start:TimerTask01");
try {
BaseFunction.console("运行:--->TimerTask01");
Thread.sleep(15000); //线程休眠3000
BaseFunction.console("休眠后--->TimerTask01");
CalendarUtils.sayTime(new Date());
// throw new RuntimeException();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 1000);
}
public static void TimerTask02(){
CalendarUtils.sayTime(new Date());
timer.schedule(new TimerTask() {
public void run() {
System.out.println("运行:TimerTask02");
CalendarUtils.sayTime(new Date());
// throw new RuntimeException("...");
}
}, 5000);
}
/**
* ScheduledExecutorService是从Java SE5的java.util.concurrent里,
* 做为并发工具类被引进的,这是最理想的定时任务实现方式。
*/
public static void TimerTaskPool(){
Runnable runnable = new Runnable() {
public void run() {
// task to run goes here
System.out.println("Hello !!");
}
};
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.scheduleAtFixedRate(runnable,10,1, TimeUnit.SECONDS);
}
}
/**
schedule(TimerTask task, Date time):安排在指定的时间执行指定的任务。
schedule(TimerTask task, Date firstTime, long period) :安排指定的任务在指定的时间开始进行重复的固定延迟执行。
schedule(TimerTask task, long delay) :安排在指定延迟后执行指定的任务。
schedule(TimerTask task, long delay, long period) :安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。
同时也重载了scheduleAtFixedRate方法,scheduleAtFixedRate方法与schedule相同,只不过他们的侧重点不同,区别后面分析。
scheduleAtFixedRate(TimerTask task, Date firstTime, long period):安排指定的任务在指定的时间开始进行重复的固定速率执行。
scheduleAtFixedRate(TimerTask task, long delay, long period):安排指定的任务在指定的延迟后开始进行重复的固定速率执行。
*/
/**
* TimerTask
TimerTask类是一个抽象类,由Timer 安排为一次执行或重复执行的任务。它有一个抽象方法run()方法,
该方法用于执行相应计时器任务要执行的操作。因此每一个具体的任务类都必须继承TimerTask,然后重写run()方法。
另外它还有两个非抽象的方法:
boolean cancel():取消此计时器任务。
long scheduledExecutionTime():返回此任务最近实际执行的安排执行时间。
*/
三、Spring自身集成的Task任务
(1)配置文件方式
<?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:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<!--此任务写到注解执行了-->
<!--<task:scheduled-tasks>-->
<!--<task:scheduled ref="simpleTaskJob" method="jobOne" cron="0/2 * * * * ?"/>-->
<!--</task:scheduled-tasks>-->
<!--新闻抓取-->
<task:scheduled-tasks>
<task:scheduled ref="simpleTaskService" method="sayHello" cron="0/2 * * * * ?" fixed-delay="1000"/>
</task:scheduled-tasks>
<!--债券抓取-->
<task:scheduled-tasks>
<task:scheduled ref="simpleTaskService" method="sayGood" cron="0/5 * * * * ?" />
</task:scheduled-tasks>
<!--上证E互动-->
<task:scheduled-tasks>
<task:scheduled ref="simpleTaskService" method="sayLove" cron="0/10 * * * * ?" />
</task:scheduled-tasks>
<!--公告-->
<task:scheduled-tasks>
<task:scheduled ref="simpleTaskService" method="sayNo" cron="0/15 * * * * ?" />
</task:scheduled-tasks>
<!--港交所股票持有数抓取-->
<task:scheduled-tasks>
<task:scheduled ref="simpleTaskService" method="sayYes" cron="0/20 * * * * ?" />
</task:scheduled-tasks>
</beans>
<!--
字段 允许值 允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
年(可选) 留空, 1970-2099 , - * /
- 区间
* 通配符
? 你不想设置那个字段
下面只例出几个式子
CRON表达式 含义
"0 0 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分每分钟一次触发
"0 0/5 14 * * ?" 每天从下午2点开始到2:55分结束每5分钟一次触发
"0 0/5 14,18 * * ?" 每天的下午2点至2:55和6点至6点55分两个时间段内每5分钟一次触发
"0 0-5 14 * * ?" 每天14:00至14:05每分钟一次触发
"0 10,44 14 ? 3 WED" 三月的每周三的14:10和14:44触发
"0 15 10 ? * MON-FRI" 每个周一、周二、周三、周四、周五的10:15触发
-->
首先要开启注解驱动
<task:annotation-driven scheduler="poolScheduler" mode="proxy"/>
<task:scheduler id="poolScheduler" pool-size="10"/>
任务类
@Service
public class SimpleTaskJob {
private int count = 0;
/**
* ApplicationContext.xml中配置了注解驱动之后完美执行任务
* 下面解除注释就可以执行
*/
@Scheduled(cron = "0/2 * * * * ?")
public void jobOne() {
System.out.println("jobOne任务中....."+(++count));
}
}
(1)最标准的写法
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<!--1.增加线程池,用于任务注册-->
<bean id="poolTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10"/>
<property name="maxPoolSize" value="20"/>
<property name="queueCapacity" value="500"/>
</bean>
<!--2.定义业务逻辑处理类-->
<bean id="simpleTask" class="com.flx.quartz.schedule.SimpleTask"/>
<!--3.增加调度业务逻辑-->
<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="simpleTask"/>
<property name="targetMethod" value="doTask"/>
</bean>
<!--4.增加调度触发器-->
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="startDelay" value="3000"/>
<property name="repeatInterval" value="2000"/>
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail"/>
<property name="cronExpression" value="0/3 * * * * ?"/>
</bean>
<!--5.增加调度-->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger"/>
<ref bean="cronTrigger"/>
</list>
</property>
<property name="taskExecutor" ref="poolTaskExecutor"/>
</bean>
</beans>
(2)复杂的Quartz调用
<?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:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<!--定时器数据,可选-->
<bean id="message" class="com.flx.app.entity.Message">
<property name="status" value="100"/>
<property name="message" value="very good"/>
</bean>
<bean id="methodTask" class="com.flx.quartz.schedule.MethodTask"/>
<!--Job任务类start-->
<!-- For times when you just need to invoke a method on a specific object -->
<bean id="simpleTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="methodTask"/>
<property name="targetMethod" value="sayHello"/>
</bean>
<bean id="firstComplexJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.flx.quartz.schedule.FirstComplexJobDetail"/>
<property name="jobDataMap">
<map>
<entry key="message" value-ref="message"/>
</map>
</property>
<!--即使trigger不关联也不会被删除-->
<property name="durability" value="true"/>
</bean>
<bean id="secondComplexJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.flx.quartz.schedule.SecondComplexJobDetail"/>
<property name="durability" value="true"/>
</bean>
<!--如果你需要更高级的设置,需要给作业传递数据,想更加灵活的话就使用这种方式。-->
<bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="com.flx.quartz.schedule.SimpleQuartzJob"/>
<property name="jobDataMap">
<map>
<entry key="message" value-ref="message"/>
</map>
</property>
<!--如果一个任务不是durable,那么当没有Trigger关联它的时候,它就会被自动删除。-->
<property name="durability" value="true"/>
<property name="description" value="简单的作业实现"/>
</bean>
<!--Job任务类end-->
<!--A简单触发器-->
<!--配置 Quartz 调度时要使用到的触发器-->
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="simpleTask"/>
<property name="startDelay" value="3000"/>
<property name="repeatInterval" value="2000"/>
<property name="repeatCount" value="4"/>
<!--<property name="startTime" value=""/>-->
</bean>
<!--B计划触发器-->
<!--这种类型更加灵活,允许你针对特定实例选择计划方案以及将来要执行的频率。-->
<bean id="firstCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="firstComplexJobDetail"/>
<property name="cronExpression" value="0/5 * * ? * *"/>
</bean>
<bean id="secondCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="secondComplexJobDetail"/>
<property name="cronExpression" value="0/10 * * ? * *"/>
</bean>
<!--将任务和计划全部整合在以前-->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTrigger"/>
<ref bean="firstCronTrigger"/>
<ref bean="secondCronTrigger"/>
</list>
</property>
</bean>
</beans>
最后开启测试类
public static void main(String[] args) {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("timer/spring-quartz-task.xml");
AbstractApplicationContext context = new ClassPathXmlApplicationContext("timer/simple-quartz-task.xml");
}