定时任务的几种实现方式

定时任务实现的几种方式:

1、JDK自带

  • (1)Timer:这是java自带的java.util.Timer类,这个类允许你调度一个java.util.TimerTask任务。使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行。一般用的较少。
  • (2)ScheduledExecutorService:也jdk自带的一个类;是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行,也就是说,任务是并发执行,互不影响。

2、Spring Task

  • Spring Task:Spring3.0以后自带的task,Spring Boot提供的用于定时任务控制的注解@Scheduled注解,可以将它看成一个轻量级的Quartz,而且使用起来比Quartz简单许多。

3、第三方任务调度框架

除了使用Spring框架提供的 @Scheduled 注解和SchedulingConfigurer接口外,还有许多第三方的任务调度库可供选择。这些库通常提供了更多的功能和灵活性,以满足各种复杂的任务调度需求。以下是一些常见的第三方任务调度库:

  • Quartz Scheduler:是一个功能强大且灵活的任务调度库,具有丰富的功能,如支持基于cron表达式的任务调度、集群支持、作业持久化等。它可以与Spring框架集成,并且被广泛应用于各种类型的任务调度应用程序中。
  • xxl-job:是一个分布式任务调度平台,提供了可视化的任务管理界面和多种任务调度方式,如单机任务、分布式任务、定时任务等。它支持任务执行日志、任务失败重试、动态调整任务执行策略等功能。
  • Elastic Job:是一个分布式任务调度框架,可以轻松实现分布式任务调度和作业执行。它提供了分布式任务执行、作业依赖关系、作业分片等功能,适用于大规模的分布式任务调度场景。
  • PowerJob:是一个开源的分布式任务调度框架,由阿里巴巴集团开发并开源。PowerJob 提供了分布式、高可用的任务调度能力,支持多种任务类型,如定时任务、延时任务、流程任务等。

目录

一、JDK自带

1、使用Timer

2、使用ScheduledExecutorService

二、Spring Task

1、基础使用案例 

2、参数说明简介

3、cron表达式

(1)cron参数配置描述

(2)cron通配符描述

4、cron案例

5、实现多任务并行(默认单线程)

6、局限性(不支持年份设定)


一、JDK自带

1、使用Timer

/*** Timer:这是java自带的java.util.Timer类** 这个类允许你调度一个java.util.TimerTask任务* 使用这种方式可以让你的程序按照某一个频度执行,但不能在指定时间运行* 【一般用的较少】*/
@Configuration
public class JDKTimerTask {@Beanpublic void test(){TimerTask timerTask = new TimerTask() {@Overridepublic void run() {System.err.println("task  run:"+ LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());}};Timer timer = new Timer();//安排指定的任务在指定的时间开始进行重复的固定延迟执行。这里是每3秒执行一次timer.schedule(timerTask,10,3000);}
}

执行结果

2、使用ScheduledExecutorService

/*** ScheduledExecutorService:也jdk自带的一个类;* 是基于线程池设计的定时任务类,每个调度任务都会分配到线程池中的一个线程去执行* 也就是说,任务是并发执行,互不影响。*/
@Configuration
public class ScheduledExecutorServiceTimerTask {@Beanpublic void test(){ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();// 参数:1、任务体 2、首次执行的延时时间//      3、任务执行间隔 4、间隔时间单位service.scheduleAtFixedRate(()->System.out.println("task ScheduledExecutorService "+ LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName()), 0, 3, TimeUnit.SECONDS);}
}

执行结果:

二、Spring Task

@Scheduled注解是Spring Boot提供的用于定时任务控制的注解,主要用于控制任务在某个指定时间执行,或者每隔一段时间执行

@Scheduled需要配合@EnableScheduling使用。使用时,将@Scheduled注解放在待定时的方法名上方,将 @EnableScheduling放在项目主启动类类名上方。@Scheduled主要有三种配置执行时间的方式:cronfixedRate 和 fixedDelay

注意:@Scheduled是不支持年份设置,spring quartz支持

1、基础使用案例 

(1)主启动类增加注解@EnableScheduling:表明开启定时任务 

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling //开启定时任务注解
public class TimedTaskDemoApplication {public static void main(String[] args) {SpringApplication.run(TimedTaskDemoApplication.class, args);}}

(2)定时任务执行方法上增加注解@Scheduled:表明该方法为定时任务需要执行的内容 

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;@Component
@Slf4j
public class TaskDemo {//    @Scheduled(cron = "0 0 4 ? * SAT")//每周六凌晨4:00@Scheduled(cron = "* * * * * *")//每秒执行一次private void doTask(){log.info("执行定时任务:" + new Date());}
}

2、参数说明简介

参数说明
cron 任务执行的cron表达式
zonecron表达时解析使用的时区,默认为服务器的本地时区。
使用java.util.TimeZone#getTimeZone(String)方法解析
GMT-8:00
fixedRate固定速率
上一次任务执行开始到下一次执行开始的间隔时间固定,单位为ms。
若在调度任务执行时,上一次任务还未执行完毕,会加入worker队列,等待上一次执行完成后,马上执行下一次任务
1000
fixedRateString与fixedRate一致,只是间隔时间使用java.time.Duration#parse解析1000或PT1S
fixedDelay 固定延迟
上一次任务执行结束到下一次执行开始的间隔时间固定,单位为ms。
1000
fixedDelayString与fixedDelay一致,只是间隔时间使用java.time.Duration#parse解析1000或PT1S
initialDelay 首次延迟多长时间后执行,单位ms。
之后按照fixedRate、fixedRateString、fixedDelay、fixedDelayString指定的规则执行,需要指定其中一个规则。
注意:不能和cron一起使用
1000
initialDelayString 与initialDelay 一致,只是间隔时间使用java.time.Duration#parse解析 1000或PT1S

关于 fixedRate 和 fixedDelay的区别:

fixedRate 的间隔时间是上次任务开始后,开始计算时间间隔,达到指定时间间隔后,开始执行下一次任务

fixedDelay 的间隔时间是上次任务结束后,开始计算时间间隔,达到指定时间间隔后,开始执行下一次任务

例如:当一个任务需要统计大量数据,并根据不用用户生成不同文件报表,并将生成的报表推送到相应的用户下,该任务有补充机制。在执行该任务时,将使用大量时间时,此时使用 fixedRate 就会造成工作队列长时间堆积,同时,如果使用 fixedRate 的话,与 cron 的作用高度重合,基本可以用 cron 表达式替代,这个情况下,使用 fixedDelay 效果更好,这是在一个任务结束后,再次执行该任务进行重试,直到所有用户都拿到相应的文件。

3、cron表达式

 cron@Scheduled的一个参数,是一个字符串,以空格隔开

@Scheduled(cron = "{秒数} {分钟} {小时} {日期} {月份} {星期}")

(1)cron参数配置描述

单位允许值允许通配符
0-59,  -  *  / 
分钟0-59,  -  *  / 
小时0-23,  -  *  / 
日期1-31,  -  *  /  ?  L  W
月份1-12或JAN-DEC(大小写均可),  -  *  /  ?
星期

1-7或SUN-SAT(大小写均可)

注:星期日为每周第一天,所以1-7表示周末到周六

,  -  *  /  ?  L  #

(2)cron通配符描述

符号含义
*所有值,在秒字段上表示每秒执行,在月字段上表示每月执行
不指定值,不需要关心当前指定的字段的值,比如每天都执行但不需要关心周几就可以把周的字段设为?
-区间或者范围,如秒的0-2 ,表示0秒、1秒、2秒都会触发
,指定值,比如在0秒、20秒、25秒触发,可以把秒的字段设为0,20,25
/递增触发,比如秒的字段上设0/3 ,表示从第0秒开始,每隔3秒触发
L最后,只允许在日字段或周字段上,在日字段上使用L表示当月最后一天,在周字段上使用3L表示该月最后一个周二
W只允许用在日字段上,表示距离最近的该日的工作日,工作日指的是周一至周五
#只允许在周字段上,表示每月的第几个周几,如2#3 , 每月的第3个周二

说明: 

在子表达式(分钟)里的“0/15”表示从第0分钟开始,每15分钟

在子表达式(分钟)里的“3/20”表示从第3分钟开始,每20分钟(它和“3,23,43”)的含义一样

“?”字符仅被用于天(月)和天(星期)两个子表达式,表示不指定值

当2个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为“?”

“L” 字符仅被用于天(月)和天(星期)两个子表达式,它是单词“last”的缩写

但是它在两个子表达式里的含义是不同的。

在天(月)子表达式中,“L”表示一个月的最后一天

在天(星期)自表达式中,“L”表示一个星期的最后一天,也就是SAT

如果在“L”前有具体的内容,它就具有其他的含义了

例如:“6L”表示这个月的倒数第6天,“FRIL”表示这个月的最一个星期五

注意:在使用“L”参数时,不要指定列表或范围,因为这会导致问题

4、cron案例

"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 ? * 6#3" 每月的第三个星期五上午10:15触发

5、实现多任务并行(默认单线程)

默认情况下如果存在多个定时任务方法是单线程同步执行

验证代码:创建两个定时任务,其中一个睡眠3秒钟

@Component
@Slf4j
public class TaskDemo {@Scheduled(cron = "* * * * * *")//每秒执行一次private void doTask(){try {Thread.sleep(3000);} catch (InterruptedException e) {throw new RuntimeException(e);}log.info("执行定时任务1:" + new Date());}@Scheduled(cron = "* * * * * *")//每秒执行一次private void doTask2(){log.info("执行定时任务【2】:" + new Date());}
}

单线程验证结果:从执行时间和线程名可以看出两个定时任务是单线程,使用的是同一个线程执行的

增加配置类:异步任务配置类进行线程池的设置

import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;import java.util.concurrent.Executor;/*** 异步任务配置类* 需要实现SchedulingConfigurer接口* 需要实现AsyncConfigurer接口*/
@Configuration
public class AsynTaskConfig implements AsyncConfigurer,SchedulingConfigurer {// 定义池子的容量private static final int CRON_POOL_SIZE = 10;// 注册定时任务线程池@Beanpublic ThreadPoolTaskScheduler getThreadPoolTaskScheduler() {ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();// 初始化线程池threadPoolTaskScheduler.initialize();// 设置池子容量threadPoolTaskScheduler.setPoolSize(CRON_POOL_SIZE);return threadPoolTaskScheduler;}@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.setTaskScheduler(getThreadPoolTaskScheduler());}//重写AsyncConfigurer的两个方法(异步的配置)@Overridepublic Executor getAsyncExecutor() {return AsyncConfigurer.super.getAsyncExecutor();}@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();}
}

异步多线程验证结果:从执行时间和线程名可以看出两个定时任务是多线程

6、局限性(不支持年份设定)

@Scheduled 的 cron 无法指定执行的年份

spring taks 不支持年位定时,它毕竟不是quartz,只是简单的定时框架,比起jdk Timer就加入了线程池而以.

一旦制定到年份,会存在问题,启动项目的时候,会一直报一个错误,大概的意思是你的定时任务将永远不会被执行,导致项目一直启动不了。

错误场景一:年份设置在第7位时报错,cron只支持到六位

错误场景二:年份设置在第6位时报错,cron第六位表示星期,内容范围只支持1-7

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/7559.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unreal游戏GPU参数详解,游戏性能优化再升级

UWA GOT Online For Unreal GPU模式近期全新发布,方便开发者从渲染和带宽的角度进行GPU分析。同时,此次更新中UWA也增加了丰富的GPU参数,涵盖了GPU SoC和GPU Counter模块。这些新增的参数不仅能够帮助Unreal开发者从宏观层面监控GPU的压力状况…

Python爬虫--Urllib基础

1. urlretrieve Urllib 库也是类似 request 库,用来解析html的 首先讲 urlretrieve 子模块 这个模块的作用是将网页下载到本地 语法: urlretrieve(网址,本地地址) 例如: 这样就可以了,他会将百度网页下载到本地D盘下&#x…

【管理咨询宝藏93】大型制造集团数字化转型设计方案

【管理咨询宝藏93】大型制造集团数字化转型设计方案 【格式】PDF版本 【关键词】国际咨询公司、制造型企业转型、数字化转型 【核心观点】 - 235页大型制造型集团数字化转型方案设计!细节非常详尽,图表丰富! - 系统架构必须采用成熟、具有国…

Kafka应用Demo:按主题订阅消费消息

安装环境 Kafka安装可参考官方网站的指导(https://kafka.apache.org/quickstart), 按步骤解压压缩包,修改配置。然后再启动zookeeper和kafka-server即可。 需要注意的一点:如果是在VMware虚拟机上启动的kafka, 需要修改一下server.properties配置文件&am…

STM32G0存储器和总线架构

文章目录 前言一、系统架构二、存储器构成三、存储器地址映射四、存储器边界地址五、外设寄存器边界地址 前言 此文章是STM32G0 MCU的学习记录,并非权威,请谨慎参考。 STM32G0主流微控制器基于工作频率可达64 MHz的高性能Arm Cortex-M0 32位RISC内核。该…

观测云 VS ELK:谁是日志监控的王者?

前言 作为 IT 信息系统运行状态感知和故障分析的重要手段,日志在行业兴起之初便为运维和开发环节所广泛应用。当应用和系统发生故障或出现问题时,日志数据成为了排查和诊断问题的重要依据。通过分析日志,开发人员和运维人员可以了解系统的运…

java JMH 学习

JMH 是什么? JMH(Java Microbenchmark Harness)是一款专用于代码微基准测试的工具集,其主要聚焦于方法层面的基准测试,精度可达纳秒级别。此工具由 Oracle 内部负责实现 JIT 的杰出人士编写,他们对 JIT 及…

PD芯片取电:电子设备的动力之源6020 6500

随着现代电子技术的迅猛发展,电源管理技术在各种电子设备中扮演着越来越重要的角色。特别是近年来,随着USB Power Delivery(PD)技术的普及,PD芯片取电技术因其高效、灵活和安全的特点,成为了电子设备充电和…

Vue + Element-plus 快速入门

1. 构建项目 npm init vuelatest # 可选项一路回车,使用默认NO,按提示执行3条命令 cd 项目名 npm install npm run dev 2. 下载element-plus npm install element-plus --save 3.替换main.js import { createApp } from vue import ElementPlus from element-plu…

相关性分析

目录 1.交叉功率谱 2. 相关系数 1.交叉功率谱 % 生成两个信号 t 0:0.001:100; x sin(2*pi*1*t)sin(2*pi*2*t); y sin(2*pi*t )sin(2*pi*2*t); % 计算交叉功率谱密度 [Pxy, F] cpsd(x, y, [], [], [], 1/(t(2)-t(1))); % 使用正确的采样频率 % 绘制交叉功率谱密度图 …

ISIS的基本配置

1.IS-IS协议的基本配置(1) 2.IS-IS协议的基本配置(2) 3.IS-IS协议的基本配置(3) 4.案例:IS-IS配置 R1的配置如下: [AR1czy]isis 1 [AR1czy-isis-1]is-level level-1 [AR1czy-isis-…

电磁兼容(EMC):静电放电(ESD)基本原理

目录 1. 静电学简史 2. 摩擦生电原理 3. 总结 静电放电是电磁兼容(EMC)系列里最让人头疼的问题之一。无论是现在还是未来,静电问题肯定是做产品设计需要重点考虑的问题。这里来聊聊关于静电放电的一些发展历程和基本原理。 1. 静电学简史…

市面上好用的AI工具有哪些?

市面上的AI工具数不胜数,选择合适自己的AI工具则需要考虑自己的需求,看是否能满足的使用需求。那么市面上又有哪些好用的AI工具呢? 泰迪智能科技拥有简单易用的大数据挖掘建模平台,能够让数据创造更大的价值。 功能板块&…

C++实现二叉搜索树(模型)

目录 1.二叉搜索树的概念 2.二叉搜索树的实现 2.1总体代码预览 2.2各个函数实现原理 链表结构体 二叉搜索树的成员变量 二叉搜索树的插入 二叉搜索树的查找 二叉搜索树的遍历 二叉搜索树的删除 1.二叉搜索树的概念 二叉搜索树又称二叉排序树,它或者是一棵空树&#…

字符设备驱动流程

字符设备驱动: linux系统驱动程序分为三大类,字符设备驱动,块设备驱动和网络设备驱动。其中字符设备驱动是使用最多的一种,从点灯到llC,SPI,音频设备等的驱动都是字符设备驱动。块设备和网络设备驱动要比字…

5.12 VUE项目实现Google 第三方登录

VUE项目实现Google 第三方登录 目录一、Google开发者平台配置1. 新建项目2. 配置 OAuth 权限请求页面并选择范围3. 启动API 和 服务 二、 登录代码实现1. 参考Google官网文档2. Google官网代码生成器3. 项目中实装 目录 一、Google开发者平台配置 Google Cloud: https://conso…

盒模型,BFC以及行内块级元素

一.盒模型篇 css基础框盒模型介绍: 当对一个文档进行布局的时候,浏览器的渲染引擎会根据标准之一的css基础框盒模型,将所有元素表示为一个个矩形的盒子,每个盒子由四部分组成,分别是内容 内边距 边框 外边距&#xff…

如何快速搭建nginx虚拟主机

华子目录 实验1:基于IP地址的虚拟主机原理 实验2:基于端口号的虚拟主机原理 实验3:基于域名的虚拟主机原理 实验1:基于IP地址的虚拟主机 原理 如果一台服务器有多个IP地址,而且每个IP地址与服务器上部署的每个网站一一…

beacon-chain+ethereum打镜像及推送镜像

部署详情 1、编写Dockerfile镜像 beacon chain对应Dockerfile文件 # 使用 Ubuntu 20.04 作为基础镜像 FROM ubuntu:20.04# 安装必要的系统库和工具 RUN apt-get update && \apt-get install -y curl && \apt-get clean# 创建存储数据的目录 RUN mkdir -p /dat…

HarmonyOS开发案例:【计算器】

介绍 基于基础组件、容器组件,实现一个支持加减乘除混合运算的计算器。 说明: 由于数字都是双精度浮点数,在计算机中是二进制存储数据的,因此小数和非安全整数(超过整数的安全范围[-Math.pow(2, 53),Math.…