定时任务的几种实现方式

news2024/9/20 7:56:03

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

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 {

	@Bean
	public void test(){
		TimerTask timerTask = new TimerTask() {
			@Override
			public 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 {

	@Bean
	public 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;

    // 注册定时任务线程池
    @Bean
    public ThreadPoolTaskScheduler getThreadPoolTaskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        // 初始化线程池
        threadPoolTaskScheduler.initialize();
        // 设置池子容量
        threadPoolTaskScheduler.setPoolSize(CRON_POOL_SIZE);
        return threadPoolTaskScheduler;
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setTaskScheduler(getThreadPoolTaskScheduler());
    }


    //重写AsyncConfigurer的两个方法(异步的配置)
    @Override
    public Executor getAsyncExecutor() {
        return AsyncConfigurer.super.getAsyncExecutor();
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return AsyncConfigurer.super.getAsyncUncaughtExceptionHandler();
    }
}

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

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

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

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

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

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

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

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

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

相关文章

基于SpringBoot+Vue社区老人健康信息管理系统

摘 要 如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统社区老人健康信息管理系统信息管理难度大,容错…

网络爬虫概述与原理

网络爬虫概述与原理 网络爬虫简介狭义上理解功能上理解常见用途总结 网络爬虫分类通用网络爬虫聚焦网络爬虫增量网络爬虫深度网络爬虫 网络爬虫流程网络爬虫采集策略深度有限搜索策略广度优先搜索策略 网络爬虫简介 通过有效地获取网络资源的方式,便是网络爬虫。网…

【SpringBoot】解锁后端测试新境界:学习Mockito与MockMvc的单元测试魔法

文章目录 前言:Java常见的单元测试框架一.Junit5基础二.SpringBoot项目单元测试1.添加依赖2.SpringBoot单元测试标准结构3.SpringBoot单元测试常用注解 三.单元测试中如何注入依赖对象1.真实注入(AutoWired、 Resource)2.Mock注入2.1.前言2.2…

数据结构复习指导之树、森林

文章目录 树、森林 考纲内容 复习提示 1.树的存储结构 1.1双亲表示法 1.2孩子表示法 1.3孩子兄弟表示法 2.树、森林、与二叉树的转换 2.1树转换为二叉树 2.2森林转换为二叉树 2.3二叉树转换为森林 3.树和森林的遍历 3.1树的遍历 3.2森林的遍历 树、森林 考纲内容…

开源推荐榜【FunClip是一款完全开源、本地部署的自动化视频剪辑工具】

FunClip是一款完全开源、本地部署的自动化视频剪辑工具,通过调用阿里巴巴通义实验室开源的FunASR Paraformer系列模型进行视频的语音识别,随后用户可以自由选择识别结果中的文本片段或说话人,点击裁剪按钮即可获取对应片段的视频(…

zookeeper安装集群模式

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 ZooKeeper是一个分…

JeeSite V5.7.0 发布,Java快速开发平台,Vite5、多项重构重磅升级

JeeSite V5.7.0 发布,Java快速开发平台,Vite5、多项重构重磅升级 升级内容 新增 参数配置 IP 地址黑白名单过滤器动态参数 新增 侧边栏是否展开第一个菜单的开关 first-open 新增 AesTypeHandler 处理字段数据加密解密或脱敏 新增 JsonTypeHandler …

247 基于matlab的梁的振型仿真

基于matlab的梁的振型仿真。利用有限元理论,求二维梁的固有频率和振型。短边固定,给定长度、横截面积,弹性模量及材料密度已知。并对比理论计算结果进行分析。各参数自己设定。程序已调通,可直接运行。 247 梁的振型仿真 固有频率…

Linux环境下parted工具使用

在工作中,我们经常会遇到大于分区大于2T的磁盘,由于系统盘最大不能超2T,我们会在做raid时将划分VD来进行装系统,但系统自动安装后无法将磁盘全部识别出来,管理员有时会要求手动对分区进行挂载,这个文档介绍…

收放卷伺服控制系统详细算法介绍(电子齿轮+张力PID卷绕轴控制功能块)

收放卷控制系统涉及的内容非常多,这里我们介绍全伺服系统利用电子齿轮指令实现主从轴的比例随动速度控制,收放卷控制算法介绍常用链接如下 1、收放卷+排线控制 收放卷+排线控制系统框图-CSDN博客文章浏览阅读24次。1、收放卷前馈量计算FC收放卷前馈量计算FC(CODESYS ST源代…

将python库下载到本地安装—Pypi官网wheel版本选择详解—小白详解版

python库—本地安装文件下载🚀 在项目中需要在内网环境下配置python的环境,因此需要将用于安装python库的文件下载到本地传到内网环境当中然后再安装,通过这契机我开始了解了一下如何离线下载安装python的第三方库,以及配置本地的…

【Docker】Ubuntu下Docker的基本使用方法与常用命令总结

【Docker】docker的基本使用方法 镜像image与容器container的关系基本命令- 查看 Docker 版本- 拉取镜像- 查看系统中的镜像- 删除某个镜像- 列出当前 Docker 主机上的所有容器,包括正在运行的、暂停的、已停止的,以及未运行的容器- 列出当前 Docker 主机…

Matlab 验证 复数的幂计算规则

复数的幂计算规则 close all a9; b0:0.1:5;result1 exp(1j*2*pi*a.*b); result2 (exp(1j*2*pi*a)).^b; idxfind(result1result2); b_idxb(idx);figure plot(b,angle(result1(:)),-r*) hold on plot(b,angle(result2(:)),bo) grid on

C++内存管理(1)

目录 1.new用法说明 2.new/delete在栈里面的运用 3.operator new/operator delete函数 4.构造函数的显式调用 5.malloc&&new&&free&&delete区别 1.new用法说明 (1)在C语言阶段,我们无论是为数组开辟空间&#x…

Disk Map for Mac,让您的Mac更“轻”松

还在为Mac磁盘空间不足而烦恼吗?Disk Map for Mac来帮您轻松解决!通过独特的TreeMap视觉显示技术,让您一眼就能看出哪些文件和文件夹占用了大量空间。只需简单几步操作,即可快速释放磁盘空间,让您的Mac更“轻”松。快来…

STL-Hashtable

hashtable hashtable是通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,这样在查找的时候就可以很快的找到该元素。 哈希函数 哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时&#xff0c…

Web UI自动化测试--PO模式

没有PO实现的测试用例的问题: 重用性低:登录功能重复可维护性差:数据和代码混合可读性差:元素定位方法杂乱(id、xpath、css混杂)可读性差:不易识别操作的含义(特别是css和xpath语法)可维护性差:如果某个元素的属性改了,你要更改多次PO(Page Object Model)页面对象模型…

Linux 第二十八章

🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C,linux 🔥座右铭:“不要等到什么都没有了…

C# SolidWorks 二次开发 -从零开始创建一个插件(3) 发布插件

五一节过完了吧,该上班学习了吧? 如何把自己开发好的程序优雅的给别人使用。 今天我们来简单讲解一下,这个之前不少粉丝咨询过相关问题,自己开发好的东西,如何给同事或者其它人使用。 先列一下使用到的主要工具&am…

计算机毕业设计】springbootBBS论坛系统

本系统为用户而设计制作 BBS论坛系统,旨在实现BBS论坛智能化、现代化管理。本BBS论坛自动化系统的开发和研制的最终目的是将BBS论坛的运作模式从手工记录数据转变为网络信息查询管理,从而为现代管理人员的使用提供更多的便利和条件。使BBS论坛系统数字化…