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

java定时任务

作者头像
栖西
发布2023-10-17 08:18:39
2070
发布2023-10-17 08:18:39
举报
文章被收录于专栏:栖西栖西
引言:知易行难

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

一、Spring定时任务

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

俩步即可实现

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

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

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

多线程实现,也很简单

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

示例:每三秒执行一次

代码语言:javascript
复制
@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
复制
通用符号:	, - * /
逗号表示枚举值,例如:在Minutes域使用5,20 表示在分钟数为5, 20的时候触发事件
减号表示范围,  例如:在Minutes域使用5-20 表示在分钟数为5到20的时候每分钟都触发一次事件
*号表示该域的任意值,假如在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
复制
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
复制
1、创建Timer对象
2、执行schedule方法

示例1

代码语言:javascript
复制
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
复制
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
复制
 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
复制
1、创建一个类实现Job
2、调用(JobDetail 和Trigger)	这个比较复杂一点

导入依赖

代码语言:javascript
复制
<dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
</dependency>

@DisallowConcurrentExecution和@PersistJobDataAfterExecution的解释:

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


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

创建一个job

代码语言:javascript
复制
@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
复制
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 删除。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引言:知易行难
  • 一、Spring定时任务
  • 二、JDK自带的Timer
  • 三、quartz框架
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档