原文地址: https://blog.csdn.net/revitalizing/article/details/61420556

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lzx_2011/article/details/61420556

定时任务几种实现方式

  1. Java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务,没怎么用过就不说了。
  2. Spring3.0以后自带的task,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。
  3. java的线程池类ScheduledExecutorService也可以实现一些简单的定时任务,周期性任务。
  4. Quartz是一个功能比较强大的的调度器,可以让你的程序在指定时间执行,也可以按照某一个频度执行,可以方便的分布式部署、便捷的监控和管理任务,适合任务很多的情况。

Spring Scheduler注解方式实现

代码还是挺少的

@Component
public class SchedulerPractice{
// @Scheduled(fixedDelay=60000)
@Scheduled(cron = "0 0/1 * * * ?")
 public void execute() {
 logger.info("every one minute------");
 }
}
  • 1
  • 2
  • 3
  • 4
  • 5

配置文件

<beans xmlns="http://www.springframework.org/schema/beans"  
       xmlns:task="http://www.springframework.org/schema/task" 
                       http://www.springframework.org/schema/task  
                       http://www.springframework.org/schema/task/spring-task-3.0.xsd
                     >
<context:annotation-config />
<!—spring扫描注解的配置 -->
<context:component-scan base-package="com.liu” />
<task:annotation-driven />
  • 1
  • 2
  • 3
  • 4
  • 5

注解@Scheduled 中有三个方法,用来对执行规则的配置:

cron:指定cron表达式,文章最后有些配置示例。

fixedDelay:即表示从上一个任务完成开始到下一个任务开始的间隔,单位是毫秒。

fixedRate:即从上一个任务开始到下一个任务开始的间隔,单位是毫秒。

执行时间可配置化

将cron表达式配置在java的properties文件或者环境变量中,是配置更灵活

xml配置方式


<task:scheduler id="myScheduler"/> <task:scheduled-tasks scheduler="myScheduler" pool-size="2" />
<task:scheduled ref=“testScheduler” method="execute()” cron="${cron_expression}"/>
</task:scheduled-tasks>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

pool-size=”2” 有多个任务可以配置以线程池执行

注解使用方式

@Scheduled(cron = "${cron_expression}")
  • 1

分布式多实例运行

scheduler与web配置在一起,在高可用的情况下,如果有多个web容器实例,scheduler会在多个实例上同时运行。

解决办法:

  1. 使用写死服务器Host的方式执行task,存在单点风险,负载均衡手动完成。(或者一台代码中配置任务,其他不配置任务)

  2. 在task的基类加入一些逻辑,当开始运行时,将状态(运行机器的IP、时间等)写入数据库、缓存(redis)或者zk,运行结束时重置状态。其它实例看到有这样的数据,就直接返回。带来的问题是: 
    一定要保证结束运行后将状态重置,否则下一个运行周期,所有的task都会返回的。 
    因为读写状态并非原子操作,偶尔也会发生task同时运行的事。

  3. 使用zk分布式锁,比如在任务执行方法上自定义注解,在注解中配置锁在zk的路径,在该注解上自定义个拦截器,在拦截器中获取zk锁。

Java线程池ScheduledExecutorService

示例代码如下

public void cronThread(){
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1); scheduledThreadPool.scheduleWithFixedDelay(new ThreadPractice(), 0, 3, TimeUnit.SECONDS); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

new ThreadPractice()是一个实现了Runnable的类。 
ScheduledExecutorService 类有两个方法

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit) public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

这两个方法和@scheduled 注解中的fixedDelay和fixedRate类似。

Quartz

Quartz框架是一个全功能、开源的任务调度服务,可以集成几乎任何的java应用程序—从小的单片机系统到大型的电子商务系统。可以方便的分布式部署、便捷的监控和管理任务,Quartz可以执行上千上万的任务调度。

核心概念

Quartz核心的概念:scheduler任务调度、Job任务、Trigger触发器、JobDetail任务细节

  • Job任务:其实Job是接口,其中只有一个execute方法, 只要实现此接口,实现execute方法即可。

  • JobDetail:任务细节,Quartz执行Job时,需要新建个Job实例,但是不能直接操作Job类,所以通过JobDetail来获取Job的名称、描述信息。

  • Trigger触发器:执行任务的规则;比如每天,每小时等。触发器有SimpleTrigger和CronTrigger,这个触发器实现了Trigger接口。对于复杂的时间表达式来说,比如每个月15日上午几点几分,使用CronTrigger,对于简单的时间来说,比如每天执行几次,使用SimpleTrigger。

  • scheduler任务调度:是最核心的概念,需要把JobDetail和Trigger注册到scheduler中,才可以执行。

quartz单机示例

使用的quartz的jar的版本是:2.2.1 ,低版本的核心类可能有些不同。

job类

public class MyJob implements Job {  

    @Override
//把要执行的操作,写在execute方法中
public void execute(JobExecutionContext arg0) throws JobExecutionException {
System.out.println(“test Quartz"+new Date());
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

测试代码

@Test
public void startJobTest() { SchedulerFactory schedulerfactory = new StdSchedulerFactory();
Scheduler scheduler = null;
try {
// 通过schedulerFactory获取一个调度器
scheduler = schedulerfactory.getScheduler(); // 创建jobDetail实例,绑定Job实现类
// 指明job的名称,所在组的名称,以及绑定job类
JobDetail job = JobBuilder.newJob(ImageTableMonitorJob.class).withIdentity("job1", "jgroup1").build(); // 定义调度触发规则
// 使用simpleTrigger规则
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("simpleTrigger", "triggerGroup")
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withRepeatCount(8)).startNow().build();
// 使用cornTrigger规则 每天10点42分
// Trigger trigger= TriggerBuilder.newTrigger().withIdentity("simpleTrigger", "triggerGroup")
// .withSchedule(CronScheduleBuilder.cronSchedule("0 42 10 * * ? *"))
// .startNow().build(); // 把作业和触发器注册到任务调度中
scheduler.scheduleJob(job, trigger); // 启动调度
scheduler.start(); } catch (Exception e) {
// e.printStackTrace();
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

spring提供了对quartz的整合,可以通过 org.springframework.scheduling.quartz.SchedulerFactoryBean 注入scheduler调度器,并且对调度器做些配置,比如使用线程池,并配置线程数量等。配置示例如下。

<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" >
<property name="taskExecutor" ref="taskExecutor" />
<property name="autoStartup" value="false"/>
</bean> <bean id="taskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="2" />
<property name="maxPoolSize" value="512" />
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

Quartz分布式原理

Quartz的集群部署方案在架构上是分布式的,没有负责集中管理的节点,而是利用数据库锁的方式来实现集群环境下进行并发控制。分布式部署时需要保证各个节点的系统时间一致。没弄过,就不细说了。

Quartz数据库核心表QRTZ_LOCKS中有5条记录CALENDAR_ACCESS,JOB_ACCESS,MISFIRE_ACCESS,STATE_ACCESS,TRIGGER_ACCESS 代表5把锁,分别用于实现多个Quartz Node对Job、Trigger、Calendar访问的同步控制。

cron表达式

字段   允许值   允许的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小时 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
年(可选) 留空, 1970-2099 , - * / - 区间
* 通配符
? 你不想设置那个字段
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

下面列出一些实例

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触发
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

参考资料

Java任务调度框架Quartz教程实例 
Spring Scheduler的使用与坑 
Quartz应用与集群原理分析

Spring Scheduler定时任务 + Quartz的更多相关文章

  1. spring -boot定时任务 quartz 基于 MethodInvokingJobDetailFactoryBean 实现

    spring 定时任务 quartz 基于  MethodInvokingJobDetailFactoryBean 实现 依赖包 如下 <dependencies> <depende ...

  2. (4) Spring中定时任务Quartz集群配置学习

    原 来配置的Quartz是通过spring配置文件生效的,发现在非集群式的服务器上运行良好,但是将工程部署到水平集群服务器上去后改定时功能不能正常运 行,没有任何错误日志,于是从jar包.JDK版本. ...

  3. Spring Boot 定时任务 Quartz 使用教程

    Quartz是一个完全由java编写的开源作业调度框架,他使用非常简单.本章主要讲解 Quartz在Spring Boot 中的使用. 快速集成 Quartz 介绍 Quartz 几个主要技术点 Qu ...

  4. java中 Spring 定时器定时任务Quartz的正确使用方法集配置

    定时任务我想大家都不默认,现在流行的框架spring就带了定时任何 我的个人网站(http://www.yzcopen.com)上用户上传的文件都是用这套定时任务执行定时清除 第一步:在applica ...

  5. spring -boot定时任务 quartz 基于 JobDetailFactoryBean实现

    这个有点小问题 尚未解决  后期优化 基于 JobDetailFactoryBean实现 依赖包 <dependencies> <dependency> <groupId ...

  6. Spring 3整合Quartz 2实现定时任务--转

    常规整合 http://www.meiriyouke.net/?p=82 最近工作中需要用到定时任务的功能,虽然Spring3也自带了一个轻量级的定时任务实现,但感觉不够灵活,功能也不够强大.在考虑之 ...

  7. spring学习总结(mybatis,事务,测试JUnit4,日志log4j&slf4j,定时任务quartz&spring-task,jetty,Restful-jersey等)

    在实战中学习,模仿博客园的部分功能.包括用户的注册,登陆:发表新随笔,阅读随笔:发表评论,以及定时任务等.Entity层设计3张表,分别为user表(用户),essay表(随笔)以及comment表( ...

  8. SpringBoot之旅 -- 定时任务两种(Spring Schedule 与 Quartz 整合 )实现

    相关文章 Spring Boot 相关文章目录 前言 最近在项目中使用到定时任务,之前一直都是使用Quartz 来实现,最近看Spring 基础发现其实Spring 提供 Spring Schedul ...

  9. Spring 3整合Quartz 2实现手动设置定时任务:新增,修改,删除,暂停和恢复(附带源码)

    摘要:在项目的管理功能中,对定时任务的管理有时会很常见.但一般定时任务配置都在xml中完成,包括cronExpression表达式,十分的方便.但是如果我的任务信息是保存在数据库的,想要动态的初始化, ...

随机推荐

  1. 000 SpringMVC介绍

    1.介绍 2.MVC 模型(Model)封装了应用程序数据,通常它们将由POJO类组成. 视图(View)负责渲染模型数据,一般来说它生成客户端浏览器可以解释HTML输出. 控制器(Controlle ...

  2. [过程记录]Centos7 下 Hadoop分布式集群搭建

    过程如下: 配置hosts vim /etc/hosts 格式: ip hostname ip hostname 设置免密登陆 首先:每台主机使用ssh命令连接其余主机 ssh 用户名@主机名 提示是 ...

  3. Java中public、protected、default和private的区别

    public: 具有最大的访问权限,可以访问任何一个在classpath下的类.接口.异常等.它往往用于对外的情况,也就是对象或类对外的一种接口的形式. protected: 主要的作用就是用来保护子 ...

  4. Ubuntu服务器的anaconda环境修复办法(自动进入base环境怎么办?)

    某天在服务器上更新了conda的版本,不知怎么回事我的python3.6就变成python2.7了,而且一进入服务器就会自动进入base环境(我的conda只装了base环境) 仔细研究了半天,才发现 ...

  5. MIT-6.828-JOS-lab5:File system, Spawn and Shell

    Lab 5: File system, Spawn and Shell tags: mit-6.828 os 概述 本lab将实现JOS的文件系统,只要包括如下四部分: 引入一个文件系统进程(FS进程 ...

  6. .NET工作准备--02基础知识

    (已过时) 框架基础,语法基础,字符串&集合&流,常见类和接口; 02.net基础(重点) -第一部分 框架基础 1.基础概念 CTS(Common Type System),CLS( ...

  7. cropper.js实现图片裁剪预览并转换为base64发送至服务端。

    一 .准备工作 1.首先需要先下载cropper,常规使用npm,进入项目路径后执行以下命令: npm install cropper 2. cropper基于jquery,在此不要忘记引入jq,同时 ...

  8. 多线程学习笔记三之ReentrantLock与AQS实现分析

    目录 简介 AQS同步状态 AQS同步队列 ReentrantLock数据结构 公平锁的获取 tryAcquire(arg) addWaiter(Node mode) acquireQueued(fi ...

  9. 【BZOJ 3028】 3028: 食物 (生成函数)

    3028: 食物 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 569  Solved: 382 Description 明明这次又要出去旅游了,和上次 ...

  10. 模板 图的遍历 bfs+dfs 图的最短路径 Floyed+Dijkstra

    广搜 bfs //bfs #include<iostream> #include<cstdio> using namespace std; ],top=,end=; ][]; ...