前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >java定时任务

java定时任务

作者头像
栖西
发布于 2023-10-17 00:18:39
发布于 2023-10-17 00:18:39
27120
代码可运行
举报
文章被收录于专栏:栖西栖西
运行总次数:0
代码可运行
引言:知易行难

这里我推荐使用第一种,Spring定时任务,简单又简介,高效

一、Spring定时任务

基于springboot创建一个项目,使用定时任务很简单

俩步即可实现

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、启动类上加注解@EnableScheduling注解开启定时任务
2、方法上加注解@Scheduled设置任务执行时间

示例 默认是单线程的定时任务

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Scheduled(fixedDelay =5*1000 )  // 每隔五秒执行一次  单位毫秒 1秒 = 1000毫秒
public void sendMsg(){
       System.out.println("当前线程名:"+Thread.currentThread().getName());
       System.err.println(DateFormat.getDateTimeInstance().format(new Date()) +"\t多喝热水");
}

这里设置的是 时间间隔 fixedDelay 和 fixedRate 效果等同

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fixedRate和fixedDelay区别:
fixedRate:它的间隔时间是根据上次任务开始的时候计时。
	例如:fixedRate = 5 * 1000 执行该方法所花的时间是2秒,那么3秒后就会再次执行该方法。
fixedDelay:它的间隔时间是根据上次的任务结束的时候开始计时的。
	例如:一个方法设置了 fixedDelay = 5*1000 当该方法某一次执行结束后,开始计算时间,当时间达到5秒,就开始再次执行该方法。

多线程实现,也很简单

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、启动类上开启异步注解	@EnableAsync
2、在定时任务的方法上加注解,设置异步执行	@Async 

示例:每三秒执行一次

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Scheduled(cron ="0/3 * * * * ?")
@Async
public void ser(){
        System.out.println("当前线程名:"+Thread.currentThread().getName());
        System.err.println(DateFormat.getDateTimeInstance().format(new Date())+"\t每3秒的时候执行");
}

cron表达式 在线生成cron表达式的网站:在线cron表达式

只要知道 , - * / 这四个和 ? 号 这五个就可以了,其他的了解一下即可

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
通用符号:	, - * /
逗号表示枚举值,例如:在Minutes域使用5,20 表示在分钟数为5, 20的时候触发事件
减号表示范围,  例如:在Minutes域使用5-20 表示在分钟数为520的时候每分钟都触发一次事件
*号表示该域的任意值,假如在Minutes域使用* 表示分钟数不受限制,每分钟都触发事件
/号表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20表示时间的分钟数为5的时候触发一次,后隔20分钟触发一次,即 25触发执行一次、45触发执行一次。

专有符号:在Spring定时任务中,除了问号,其他都不支持!
?	问号:只能用在日和星期俩个域,他俩互斥,必须对其中一个进行设置,使用的场景不关心这个值
L	大写字母L,只能出现在日和星期俩个域,如果在DayOfWeek使用5L,意味着在最后的一个星期四触发
W	大写字母W,表示有效工作日(周一到周五),只能出现在DayOfMonth域,系统将在离指定日期的最近有效工作日触发事件
LW	这俩个字符可以连用,表示在某个月最后一个工作日
#	用于确定每个月的第几个星期几,只能出现在DayofWeek域,例如:4#2,表示某月的第二个星期三
C	只能用在DayofMonth和DayofWeek俩个域,需要关联日历,如果没关联可以忽略。

拓展一下: @Scheduled()的8个参数的意思

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、cron
	接受一个cron表达式
2、zone
	时区,接受一个java.util.TimeZone#ID
	默认是一个空字符串,取服务器所在地的时区,该字段一般留空,我们一般使用的时区:Asia/Shanghai
3、fixedDelay
	上一次执行完 间隔多长时间再次执行
4、fixedDelayString
	和fixedDelay 意思相同,只是使用字符串的形式,唯一不同的是支持占位符
5、fixedRate
	上一次开始执行时间点之后多长时间再执行
6、fixedRateString
	与fixedRate 意思相同,只是使用字符串的形式,唯一不同的是支持占位符
7、initialDelay
	第一次延迟多长时间后再执行
8、initialDealyString
	与initialDelay 意思相同,只是使用字符串的形式,唯一不同的是支持占位符

二、JDK自带的Timer

使用也是两步

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、创建Timer对象
2、执行schedule方法

示例1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) {
    // 创建timer对象
    Timer timer = new Timer();

    // 执行定时任务
    // 参数1  timerTask对象 定时任务对象
    // 参数2  任务什么时候启动
    // 参数3  执行任务的时间间隔
    timer.schedule(new TimerTask() {
        @Override
        public void run() {
            System.out.println("定时任务1===\t"+ DateFormat.getDateTimeInstance().format(new Date()));
        }
    },new Date(),1000);
}

示例2

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public static void main(String[] args) {
        // 创建timer对象   任务启动
        Timer timer = new Timer();
        for (int i = 0; i < 3; i++) {
            StudyTimerTask studyTimerTask = new StudyTimerTask("执行者"+i+"号");
            // 立刻执行  每隔2秒执行一次  任务添加
            timer.schedule(studyTimerTask,new Date(),2000);
//            timer.schedule();     		丢任务  少执行
//            timer.scheduleAtFixedRate();  提前执行,执行时间会乱
            // 单线程  任务阻塞  任务超时
        }
    }

//另一个类
class StudyTimerTask extends TimerTask{

    private String name;

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

    @Override
    public void run() {
        try {
            System.out.println(name+"\t任务开始时间\t"+DateFormat.getDateTimeInstance().format(new Date()));
            Thread.sleep(5000);
            System.err.println(name+"\t任务结束时间\t"+DateFormat.getDateTimeInstance().format(new Date()));
            // 线程池执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

多线程模拟示例 示例3

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 public static void main(String[] args) {
       // 线程池执行
       // 先创建一个线程池
        ScheduledExecutorService scheduledThreadPool  = Executors.newScheduledThreadPool(5);
        for (int i = 0; i < 2; i++) {
            StudyTimerTask2 task2 = new StudyTimerTask2("多线程启动" + i + "号");
            // 参数1 任务  参数2 延迟时间  参数3 间隔时间  参数4 时间单位
            scheduledThreadPool.scheduleAtFixedRate(task2,0,2, TimeUnit.SECONDS);
        }
    }

class StudyTimerTask2 implements Runnable{

    private String name;

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

    @Override
    public void run() {
        try {
            System.out.println(name+"\t任务开始时间\t"+DateFormat.getDateTimeInstance().format(new Date()));
            Thread.sleep(5000);
            System.err.println(name+"\t任务结束时间\t"+DateFormat.getDateTimeInstance().format(new Date()));
            // 线程池执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

三、quartz框架

这里我记录一下源生的quartz的使用

使用详情

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、创建一个类实现Job
2、调用(JobDetail 和Trigger)	这个比较复杂一点

导入依赖

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
</dependency>

@DisallowConcurrentExecution和@PersistJobDataAfterExecution的解释:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
禁止并发地执行同一个job定义(jobDetail定义的多个实例) 加在类上面
@DisallowConcurrentExecution


如果一个任务不是持久化的,则当没有触发器关联它的时候,quartz会从scheduled删除它
将参数进行持久化(对trigger中的dataMap无效)
@PersistJobDataAfterExecution

创建一个job

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class MyJob implements Job {

    // 另一种存值的方式
    private String address;

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDataMap jobDetailMap = jobExecutionContext.getJobDetail().getJobDataMap();
        JobDataMap jobTriggerMap = jobExecutionContext.getTrigger().getJobDataMap();
        jobDetailMap.put("count",jobDetailMap.getIntValue("count")+1);
        System.out.println("jobDetailMap=\t"+jobDetailMap.getString("name"));
        System.out.println("jobDetailMap=\t"+jobDetailMap.getString("age"));
        System.out.println("jobTriggerMap=\t"+jobTriggerMap.getString("sex"));
        // 要是有键名相同的话  这里会覆盖掉
        JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap(); // 就是把前俩个的map都获取
        System.err.println("address=\t"+address);
        System.err.println("调的次数count=\t"+jobDetailMap.getInt("count"));
        System.err.println("mergedJobDataMap\tsex="+mergedJobDataMap.get("sex")+"\tname="+mergedJobDataMap.get("name"));
        System.err.println("MyJob is execute\t"+ DateFormat.getDateTimeInstance().format(new Date()));
        // 测试每次调用任务的时候都创建一个新的实例
        System.out.println("jobDetail:\t"+System.identityHashCode(jobExecutionContext.getJobDetail()));
        System.out.println("job:\t"+System.identityHashCode(jobExecutionContext.getJobInstance()));
    }
}

启动

使用usingJobData 进行传参,可以理解为往map中添加键值对

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class TestJob {
    public static void main(String[] args) {
        int count=0; // 统计定时任务调了几次

        JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
                .withIdentity("任务名叫小明","任务组为group1")
                // 理解为启动定时任务的时候 往业务逻辑传递一些参数
                .usingJobData("name","张三")     // 存放map 键值的形式  任务可以获取参数
                .usingJobData("age","18")
                .usingJobData("count",count)
                .usingJobData("address","上海浦东区")
                .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                .withIdentity("触发器1","触发器组1")
                .usingJobData("sex","男")   // 设置键值
                // Job 通过set设置值的话, trigger的值会覆盖jobDetail的值
                .usingJobData("address","北京市")
                .startNow()  // 立即启动  指定时间启动的话 startAt
                .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)
                        .repeatForever())        // 一直执行
                        .build();

        try {
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            scheduler.scheduleJob(jobDetail,trigger);
            scheduler.start();
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-11-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
2 条评论
热度
最新
我说这么眼熟 简书已经关注了哈哈
我说这么眼熟 简书已经关注了哈哈
回复回复点赞举报
写的太好了
写的太好了
回复回复点赞举报
推荐阅读
Android SystemServer启动(二)
在之前已经分析到,通过SystemServer的run方法进入到SystemServer内部逻辑。
Rouse
2021/01/12
9630
笔记:Zygote和SystemServer进程启动过程
用户1172465
2018/01/08
8290
Android系统之System Server大纲
System Server是android 基本服务的提供者,是android系统运行的最基本需求,所有server运行在一个叫system_process的进程中,system_process进程是android java虚拟机跑的第一个进程,从Zygote 创建而来,是andorid系统最重要的java虚拟机。可以说,整个android系统的业务都是围绕system server而展开,所以,当system_process死掉了,手机必须重启。
233333
2024/07/02
2900
BAT大厂Android工程师带你学习Framework内核解析
对于Android开发,干上几年后,都要进阶,或者直接转行了。如果你还在干Android,想要进阶 对Framework的了解是必不可少的过程,下面就开始进入今天的主题吧。
te大大
2021/11/15
4010
SystemServer 进程启动过程
SystemServer进程主要用于启动系统服务,诸如AMS、WMS、PMS都是由它来创建的。在系统的名称为"system_server",Android核心服务都是它启动,它是非常重要。
八归少年
2023/12/30
2260
ActivityManagerService 启动初探
在之前的Android SystemServer启动(二)中,分析到在SystemServer中会启动大量的Service,其中就有一个比较特殊的Service,它就是ActivityManagerService。
Rouse
2021/01/12
9500
Android Framework学习(三)之SyetemServer进程启动解析
从上篇博客中,我们知道了Zygote进程启动了SyetemServer进程,本篇博客我们就一起来学习SyetemServer进程。
老马的编程之旅
2022/06/22
4250
[Android][Framework] 添加系统服务
做系统开发,有时候需要自己定义一些接口供App使用, 同时为了方便维护管理,就会需要自己建立一个服务,把新的功能集中在一起。下面就是新建一个系统服务的基本步骤。
wOw
2018/09/15
1.5K0
图解 | 一图摸清Android系统服务
在日常开发中,可以通过Context.getSystemService()在自己的应用程序里获取到系统服务:
Holiday
2020/10/29
8120
图解 | 一图摸清Android系统服务
Android系统启动之SystemServer
SystemServer是由Zygote启动的. 源码路径frameworks/base/services/java/com/android/server/SystemServer.java
李小白是一只喵
2020/04/23
2.4K0
Android系统启动之SystemServer
ActivityManagerService启动过程分析
之前讲Android的View的绘制原理和流程的时候,讲到过在Android调用setContentView之后,Android调用了一个prepreTravle的方法,这里面就提到了ActivityManagerService。 ActivityManagerService提供的主要功能:        (1)统一调度各应用程序的Activity        (2)内存管理        (3)进程管理 上一篇我们分析Android启动过程的文章中我们分析到了SystemServer,当时我们只是简单的
xiangzhihong
2018/02/05
9640
ActivityManagerService启动过程分析
系统中的大管家—SystemServer进程
上篇说到Android系统的启动流程,Zygote进程fork的第一个进程就是SystemServer进程。
码上积木
2021/01/12
5770
Android之SystemServer介绍(二)
上文讲到执行到SystemServer类的main函数。MethodAndArgsCaller函数在Zygote.java类中:
李小白是一只喵
2021/03/16
3980
Android之SystemServer介绍(二)
[Android][Framework] 添加系统服务
做系统开发,有时候需要自己定义一些接口供App使用, 同时为了方便维护管理,就会需要自己建立一个服务,把新的功能集中在一起。下面就是新建一个系统服务的基本步骤。
wOw
2020/01/20
1.1K0
ActivityManager 讲解
大家好,又见面了,我是你们的朋友全栈君。 1.ActivityManager 是 android 框架的一个重要部分,它负责一新 ActivityThread 进程创建, Activity 生命周期的维护,本 blog 就是着手对 ActivityManager 框架作一个整体的了解 2. 先看一个静态类结构图:
全栈程序员站长
2022/10/04
3810
[Android][Framework] Android O SystemServer启动流程
SystemServer通过ZygoteInit.java反射启动,首先会进入main方法,main会构造一个新的SystemServer,然后运行run()方法
wOw
2018/09/18
3K0
[Android][Framework] Android O SystemServer启动流程
Android系统服务(SystemService)简介
我们在Android开发过程中经常会用到各种各样的系统管理服务,如进行窗口相关的操作会用到窗口管理服务WindowManager,进行电源相关的操作会用到电源管理服务PowerManager,还有很多其他的系统管理服务,如通知管理服务NotifacationManager、振动管理服务Vibrator、电池管理服务BatteryManager…… 这些Manager提供了很多对系统层的控制接口。对于App开发者,只需要了解这些接口的使用方式就可以方便的进行系统控制,获得系统各个服务的信息,而不需要了解这些接口的具体实现方式。而对于Framework开发者,则需要了解这些Manager服务的常用实现模式,维护这些Manager的接口,扩展这些接口,或者实现新的Manager。
233333
2020/03/18
1.9K0
APK安装流程详解7——PackageManagerService的启动流程(上)
我们看到在SystemServer无参构造函数里面就是初始化mFactoryTestMode
隔壁老李头
2018/08/30
2.4K0
APK安装流程详解7——PackageManagerService的启动流程(上)
征服Android面试官路漫漫(四):5 张图带你搞懂Android系统启动的核心流程
init进程是Linux内核启动完成后在用户空间启动的第一个进程,主要负责初始化工作、启动属性服务、解析init.rc文件并启动Zygote进程。
Android技术干货分享
2020/11/06
6590
征服Android面试官路漫漫(四):5 张图带你搞懂Android系统启动的核心流程
Android启动系列之二:SystemServer和Launcher
上一篇中我们讲到Zygote进程启动了SystemServer进程,那么来看看它是如何处理System进程的。先来一个完整的时序图,如下:
BennuCTech
2024/05/17
2030
Android启动系列之二:SystemServer和Launcher
相关推荐
Android SystemServer启动(二)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验