Quartz定时任务基础

springBoot有一个定时执行某个方法的 注解:

@Scheduled

可以满足挺多的需求,但是到了一些场景,就显得比较麻烦,比如:

机器待机五分钟后执行切换待机状态。如果是按照使用@Scheduled注解,就得持久化一个表,里面存放机器信息,转换时间,然后@Scheduled一个方法,每隔一定时间扫描全表,查询需要转换的机器。

还有一种有趣的解决办法:

它会定义一个小顶堆,存放需要执行的任务(主要还是存放的该任务的执行时间),

小顶堆结构;

添加任务只需要在最后一个位置加上,然后上浮操作(和父级对比,父级更大就交换,父级小就不动,一直对比,直到父级小不动),所以会发现,每次都是操作父子级,如何快速找到父级,成了最大问题,于是,存储结构选择了数组:

只需要将子集下标/2=取整,就是父级下标。

存入:

也就是说,每次只需要判断顶部数据是否可以执行即可,比上面那种直接扫描全表性能更快。

执行一个任务后,就会刷新顶堆,拿出最后一个。

取出:

package com.quxiao;

import java.time.LocalTime;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @program: springBoot
 * @author: quxiao
 * @create: 2023-11-18 11:00
 **/
public class t1 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        for (int i = 0; i < 2; i++) {
            TimerTask timerTask = new TimerTest1("" + i);
            timer.schedule(timerTask, new Date(), 2000);
        }
    }

    static final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 20, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(60));

    static class TimerTest1 extends TimerTask {
        String name;

        public TimerTest1() {

        }

        public TimerTest1(String name) {
            this.name = name;
        }

        @Override
        public void run() {
//如果不使用线程池运行,会导致延迟执行,因为run方法是阻塞的,无法做到异步
            poolExecutor.execute(() -> {
                System.out.println(name + ": " + (LocalTime.now().toString()));
                try {
                    TimeUnit.SECONDS.sleep(3);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
}

Timer是java自带的一个定时任务,定时执行指定的方法,

还有一种就是时间轮,Cron表达式,每个位置指定日期,这里我们使用quartz框架来进行调度器:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

直接使用和springBoot项目运行

首先定义执行什么,怎么执行,以及储存任务

执行什么:

package com.quartz.jop;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.time.LocalTime;

/**
 * @program: springBoot
 * @author: quxiao
 * @create: 2023-11-18 20:00
 **/
public class TestJop implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println(LocalTime.now().toString());
    }
}

只有实现了job接口的类才能执行,我们可以在里面执行任何东西。

然后就是怎么执行:

package com.quartz.controller;

import com.quartz.jop.TestJop;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @program: springBoot
 * @author: quxiao
 * @create: 2023-11-18 20:04
 **/
@RestController
public class t1 {
    @RequestMapping("test1")
    public void test1() {
        //定义需要执行的方法(就是实现类)
        JobDetail jobDetail = JobBuilder.newJob(TestJop.class)
                .withIdentity("job1", "group1")
                .build();
        //如何执行,多少秒一次,什么时候执行,都是在这里定义
        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "trigger1")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever())
                .build();
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            //储存起来
            scheduler.scheduleJob(jobDetail, trigger);
            //启动    
            scheduler.start();
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        } finally {
        }

    }
}

在定义定时器时,可以将需要的值传入:

package com.quartz.controller;

import com.quartz.jop.TestJop;
import com.quartz.jop.t2;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @program: springBoot
 * @author: quxiao
 * @create: 2023-11-18 20:04
 **/
@RestController
public class t1 {
    @RequestMapping("test1")
    public void test1() {
        JobDetail jobDetail = JobBuilder.newJob(TestJop.class)
                .withIdentity("job1", "group1")
                .usingJobData("name","你爹")
                .build();

        SimpleTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "trigger1")
                .usingJobData("name","ty")
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).withRepeatCount(2))
                .build();
        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.scheduleJob(jobDetail, trigger);
            scheduler.start();
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        } finally {
        }

    }
}

其实就是一个map

取出:

package com.quartz.jop;

import org.quartz.*;

import java.time.LocalTime;

/**
 * @program: springBoot
 * @author: quxiao
 * @create: 2023-11-18 20:00
 **/
public class TestJop implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {

        Trigger trigger = context.getTrigger();
        JobDataMap map = trigger.getJobDataMap();
        System.out.println(map.get("name"));

        System.out.println(LocalTime.now().toString());

        JobDetail jobDetail = context.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        System.out.println(jobDataMap.get("name"));

    }
}

还可以直接把trigger 和jobDetail取出来:

JobDataMap mergedJobDataMap = context.getMergedJobDataMap();

不过很显然,可是不能重复的,map嘛

还有一点就时,调度器默认是并行的:

package com.quartz.jop;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * @program: springBoot
 * @author: quxiao
 * @create: 2023-11-18 20:00
 **/
public class TestJop implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
            System.out.println(1123211);
        try {
            TimeUnit.SECONDS.sleep(new Random().nextInt(3));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        
//        JobDataMap mergedJobDataMap = context.getMergedJobDataMap();
//        System.out.println(mergedJobDataMap.get("name"));

    }
}

 也就是说,不管上一个任务是否执行完毕,我到了点,本次任务必然执行-。

使用@DisallowConcurrentExecution注解可以变为串行,也就是同步执行

@PersistJobDataAfterExecution可以让jobDetail的jobDataMap一直保存

package com.quartz.jop;

import org.quartz.*;

/**
 * @program: springBoot
 * @author: quxiao
 * @create: 2023-11-18 20:00
 **/
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class TestJop implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDetail jobDetail = context.getJobDetail();
        JobDataMap jobDataMap = jobDetail.getJobDataMap();
        jobDataMap.put("name", jobDataMap.get("name") + "123");
        System.out.println(jobDataMap.get("name"));
    }
}





cron 模式定时器

前面用的是基础的执行多少次,指定时间执行还是得用cron方式,注意springBoot有自带的cron执行

@Scheduled

注解,但是它只能标识在方法上,也就是说只能某个方法,并不能达到前提条件,例如:

设备闲置5分钟,改为待机状态,只要在五分钟内运行,我们就把这个定时任务删掉就好。

package com.quartz.util;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @program: springBoot
 * @author: quxiao
 * @create: 2023-11-26 10:56
 **/
public class DateUtil {
    /**
     * @param date 指定日期
     * @return 返回指定日期的cron表达式
     */
    public synchronized static String getCron(Date date) {
        String dateFormat = "ss mm HH dd MM ? yyyy";

        SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
        String formatTimeStr = null;
        if (date != null) {
            formatTimeStr = sdf.format(date);
        }
        return formatTimeStr;
    }

    /**
     * @param date 指定日期
     * @param unit 时间单位
     * @param number 增加多少
     * 增加指定时间
     */
    public synchronized static Date addTime(Date date, TemporalUnit unit,long number){
        LocalDateTime date1 = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        LocalDateTime nextWeek = date1.plus(number, unit);
        return Date.from(nextWeek.atZone(ZoneId.systemDefault()).toInstant());
    }
}

 先给一个时间转换的工具类

使用cron方式只需要将触发器改了就行: (接上序的基础springboot代码)

  @Autowired
    Scheduler scheduler;

    @PostMapping("test1")
    public void test1() {
        JobDetail jobDetail = JobBuilder.newJob(TestJop.class)
                .withIdentity("job1", "group1")
                .build();

        Date date = DateUtil.addTime(new Date(), ChronoUnit.SECONDS, 5);
        //cron表达式
        String cron = DateUtil.getCron(date);
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("trigger1", "trigger1")
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))//达到指定时间执行
                .build();
        try {
            scheduler.scheduleJob(jobDetail, trigger);
            scheduler.start();
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

 

 我们之所以使用这个框架,就是因为他可以支持删除、暂停、定时任务,所以就能够把定时任务存起来持久化管理。

删除、暂停、恢复定时任务

 @PostMapping("test2")
    public void t2() {
        try {
            JobKey key = new JobKey("job1","group1");
            scheduler.deleteJob(key);
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
    }

在这里我们前面定义的group分组就起到作用了,通过指定定时任务名job金额分组名group。

所以剩余两个操作也是一样:

  @PostMapping("test3")
    public void t3() {
        try {
            JobKey key = new JobKey("job1", "group1");
            scheduler.pauseJob(key);
            for (int i = 0; i < 10; i++) {
                System.out.println("暂停中");
                TimeUnit.SECONDS.sleep(1);
            }
            scheduler.resumeJob(key);
        } catch (Exception e) {
        }
    }

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java SE】 带你走近Java的抽象类与接口

&#x1f339;&#x1f339;&#x1f339;【JavaSE】专栏&#x1f339;&#x1f339;&#x1f339; &#x1f339;&#x1f339;&#x1f339;个人主页&#x1f339;&#x1f339;&#x1f339; &#x1f339;&#x1f339;&#x1f339;上一篇文章&#x1f339;&#x1f339;&…

2018年3月26日 Go生态洞察:Go包版本管理提案分析

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

java springboot测试类虚拟MVC环境 匹配请求头指定key与预期值是否相同

上文 java springboot测试类虚拟MVC环境 匹配返回值与预期内容是否相同 (JSON数据格式) 版 中 我们展示 json匹配内容的方式 那么 本文我们来看看Content-Type属性的匹配方式 首先 我们从返回体可以看出 Content-Type 在请求头信息 Headers 中 我们直接将测试类代码更改如下 …

C#,《小白学程序》第二十七课:大数四则运算之“运算符重载”的算法及源程序

1 文本格式 using System; using System.Text; using System.Collections; using System.Collections.Generic; /// <summary> /// 大数的四则&#xff08;加减乘除&#xff09;运算 /// 及其运算符重载&#xff08;取余数&#xff09; /// </summary> public cl…

在项目中集成marsUI

拷贝文件夹到目标项目 集成 安装相关依赖 npm i --save ant-design-vue4.x npm i less npm i nprogress npm i consola npm i echarts npm i vue-color-kit npm i icon-park/svg npm i vite-plugin-style-import 配置Vite文件 使用 效果

Leetcode—828.统计子串中的唯一字符【困难】

2023每日刷题&#xff08;四十一&#xff09; Leetcode—828.统计子串中的唯一字符 算法思想 枚举所有种类字母在s中出现的位置&#xff0c;分别统计只包含这个字母不包含该类字母中其他字母的子串个数 实现代码 int uniqueLetterString(char* s) {int len strlen(s);cha…

电子学会C/C++编程等级考试2022年06月(二级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:小白鼠再排队 N只小白鼠(1 < N < 100),每只鼠头上戴着一顶有颜色的帽子。现在称出每只白鼠的重量,要求按照白鼠重量从小到大的顺序输出它们头上帽子的颜色。帽子的颜色用 “red”,“blue”等字符串来表示。不同的小白…

十分钟让你搞懂JVM中的GC垃圾回收机制(分代回收)

文章目录 0. 为什么要有垃圾回收?1. 垃圾回收哪个内存区域?2. 如何找到垃圾(死亡对象的判断)2.1 引用计数法2.2 可达性分析法2.3 两种算法的差别 3. 如何清理垃圾(死亡对象的回收)3.1 标记-清楚法3.2 复制法3.3 标记-整理法 4. JVM使用的回收方法4.1 什么是分代回收4.2 哪些对…

【Linux】:信号的产生

信号 一.前台进程和后台进程1.前台进程2。后台进程3.总结 二.自定义信号动作接口三.信号的产生1.键盘组合键2.kill信号进程pid3.系统调用1.kill函数2.raise函数3.abort函数 四.异常五.软件条件六.通过终端按键产生信号 一.前台进程和后台进程 1.前台进程 一个简单的代码演示 …

跟着chatgpt学习|1.spark入门

首先先让chatgpt帮我规划学习路径&#xff0c;使用Markdown格式返回&#xff0c;并转成思维导图的形式 目录 目录 1. 了解spark 1.1 Spark的概念 1.2 Spark的架构 1.3 Spark的基本功能 2.spark中的数据抽象和操作方式 2.1.RDD&#xff08;弹性分布式数据集&#xff09; 2…

JAVA时间常用操作工具类

小刘整理了JAVA中对时间的常用操作&#xff0c;封装了几种方法&#xff0c;简单方便&#xff0c;开箱即用。时间转字符串格式&#xff0c;字符串转时间&#xff0c;以及过去和未来的日期。除此之外&#xff0c;还新增了时间戳之差计算时分秒天的具体方案。 public static void …

【力扣:1707 1803】0-1字典树

思路&#xff1a;树上每个节点存储拥有该节点的数组元素的最小值&#xff0c;left节点表示0&#xff0c;right节点表示1&#xff0c;构建完成后遍历树当子节点没有比mi小的元素时直接输出-1&#xff0c;否则向下构造。 struct tree{int m;tree*leftnullptr,*rightnullptr;tree…

智能优化算法应用:基于海鸥算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于海鸥算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于海鸥算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.海鸥算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…

养生馆服务预约会员管理系统小程序效果如何

中医养生馆的全国数量逐渐增加&#xff0c;各种疾病困扰下&#xff0c;有些病往往通过养生馆即可治好&#xff0c;比如常见的针灸、按摩、药理滋补、切脉等&#xff0c;都有很高的市场需求度&#xff0c;而随着众多商家入局赛道及消费升级&#xff0c;传统中医养生馆经营痛点也…

深度学习第3天:CNN卷积神经网络

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​ 文章目录 介绍 CNN的主要结构 卷积层 激励层 池化层 Kears搭建CNN 搭建代码 直观感受卷积的作用 结语 介绍 卷积神经网络&#xff08;Convol…

印刷基板开孔机上的直线导轨怎么安装?

直线导轨是属于高精度的传动元件&#xff0c;作为印刷基板开孔机重要的传动元件&#xff0c;倘若安装不当&#xff0c;严重则无法正常作业&#xff0c;轻则影响直线导轨的精度和寿命。那么&#xff0c;印刷基板开孔机的直线导轨是如何安装的呢&#xff1f; 在安装前&#xff0c…

C语言编译过程再解析

多年以前,分析过编译过程,并写了一篇博客,现在对编译过程有了更广阔的认识,记录在此 编译过程 中的 链接与 编译 编译过程分为1. 预处理2. 编译3. 汇编4. 链接其中有 2个过程比较特殊,1. 编译2. 链接对于C程序来说,链接分为提前链接(静态链接)对应下图第1行运行时链接(动态链…

Spring Boot 改版如何解决?使用阿里云创建项目、使用IDEA进行创建

接上次博客&#xff1a;JavaEE进阶&#xff08;2&#xff09;SpringBoot 快速上手&#xff08;环境准备、Maven&#xff1a;核心功能&#xff0c;Maven仓库、第⼀个SpringBoot程序&#xff1a;Spring介绍&#xff0c;Spring Boot介绍、创建项目&#xff09;-CSDN博客 目录 使…

深度学习技巧应用30-深度学习中的GPU的基本架构原理与应用技巧

大家好,我是微学AI,今天给大家介绍一下深度学习技巧应用30-深度学习中的GPU的基本架构原理与应用技巧,GPU是一种专门用于处理大量并行操作的硬件设备,它的架构设计主要是为了图形渲染。然而,由于其并行处理能力,现在广泛应用于深度学习、科学计算等领域。主要的GPU制造商…

智能优化算法应用:基于蝗虫算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于蝗虫算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于蝗虫算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.蝗虫算法4.实验参数设定5.算法结果6.参考文献7.MATLAB…