一、cron表达式

语法:秒 分 时 日 月 周 年(Spring 不支持)
官方网站:http://www.quartz-scheduler.org/documentation/quartz-2.3.0/tutorials/crontrigger.html
在这里插入图片描述
特殊字符:
,:枚举;
(cron=“7,9,23 * * * * ?”):任意时刻的 7,9,23 秒启动这个任务;

-:范围:
(cron=“7-20 * * * * ?”):任意时刻的 7-20 秒之间,每秒启动一次

*:任意;
指定位置的任意时刻都可以

/:步长;
(cron=“7/5 * * * * ?”):第 7 秒启动,每 5 秒一次;
(cron=”*/5 * * * * ?”):任意秒启动,每 5 秒一次;
斜杠前面的是启动时间点,后边的是步长。
如果没有斜杠表示步长为1s

?:(出现在日和周几的位置):为了防止日和周冲突,在周和日上如果要写通配符使
用?,一般情况只有一个问号
(cron=”* * * 1 * ?”):每月的 1 号,启动这个任务;

L:(出现在日和周的位置)”,
last:最后一个
(cron=”* * * ? * 3L”):每月的最后一个周二

W:
Work Day:工作日
(cron=”* * * W * ?”):每个月的工作日触发
(cron=”* * * LW * ?”):每个月的最后一个工作日触发

#:第几个
(cron=”* * * ? * 5#2″):每个月的第 2 个周 4

在这里插入图片描述

二、SpringBoot 整合

注意:springboot中,支持6个参数,不支持年的选择,在设置第6个参数(周)时 用1-7分别代表周一到周日, 而原生cron表达式时1-7表示周日-周六。

2.1 基本使用

第一步:开启定时功能注解
@EnableScheduling
第二步:在方法上标注定时
@Scheduled
第三步:测试

     @Scheduled(cron = "*/1 * * ? * 2")
     public void hello() {
         log.info("hello..."+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
         try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }

     }

2.2 异步任务

在这里插入图片描述
我们可以设置 @Scheduled异步执行
方法一:在配置文件中配置(这种放在某些boot版本不起作用,所以不推荐)

spring.task.scheduling.pool.size=10

方法二:★异步任务
第一步:开启异步任务
@EnableAsync
@EnableScheduling


@EnableAsync
@EnableScheduling
@Configuration
public class ScheduledConfig {

}

在方法上加上异步注解
@Async

     @Async
     @Scheduled(cron = "*/1 * * ? * 2")
	public void hello() {
		log.info("hello..."+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
		try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); }

	}

第二步:配置线程池

#异步任务的线程池
spring.task.execution.pool.core-size=4
spring.task.execution.pool.max-size=50

第三步:测试
在这里插入图片描述
总结:
@EnableAsync + @Async 可以为任何方法创建异步任务。

三、★实战

通过Scheduling + 线程池+线程排列

3.1 背景

比如小区门口有个闸机,闸机会抓取车辆的出入记录保存到闸机服务器,一个闸机对应一个服务器,服务器提供了rest接口可以获取某一时间段的过车记录。一个小区可能有多个闸机。
我们的需求时要把小区的过车记录抓取保存到我们的平台上。

3.2 分析

首先抓起肯定不是一次性的,为了保证实时效果我们需要没5s请求一次闸机把数据获取到。但是一个小区有多个闸机如果我们用循环的方式一个一个获取,总时间就是所有闸机请求的和,(线程充足的情况下)如果用多线程就是最慢的那个闸机请求的时间。

3.3 代码过程

main方法用的springboot

@SpringBootApplication
public class ScheduledThreadApplication {

    public static void main(String[] args) {
        SpringApplication.run(ScheduledThreadApplication.class, args);
    }

}

schedu任务,注意这几个配置
@Component 表示加入到ioc容器
@Configuration 表示时配置文件
@EnableAsync 开启异步,并不代表异步,要异步需要与@Async共同使用
@EnableScheduling 允许定时

@Slf4j
@Component
@Configuration
@EnableAsync
@EnableScheduling
public class ScheduleTask {

    @Autowired
    private  Car car;
    @Scheduled(cron = "*/2 * * ? * ?")
    public void sendMqCarInAndCarOut1() throws InterruptedException {
        System.out.println("★★★★★★--1111111111111111111-》" +Thread.currentThread() +"..." + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
        TimeUnit.SECONDS.sleep(10);
        car.carInOut();
        System.out.println("★★★★★★--1111111111111111111------------end-》" );
    }

}

业务代码

@Component
public class Car {
    /***
     * 线程池----------start
     */
    private static int corePoolSize = 10;
    private static int maxPoolSize = 200;
    private static int queueCapacity = 10;
    static ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

    static {
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.initialize();
    }
    /***
     * 线程池----------end
     */

    // 4个业务线
    private int count = 4;

    public void carInOut() {
        try {
            // 把所有的任务放在集合中用于下面进行阻塞
            CompletableFuture[] data = new CompletableFuture[count];
            for (int i = 0; i < count; i++) {
                CompletableFuture infoFuture = CompletableFuture.supplyAsync(() -> {
                    try {
                        TimeUnit.SECONDS.sleep(2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println("★★★★★★---》" + Thread.currentThread() + "业务---"+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                    return null;
                }, executor);
                data[i] = infoFuture;
            }
            // 等待所有的任务完成后才执行后面的代码
            CompletableFuture.allOf(data).get();
        } catch (Exception e) {
            System.out.println("★★★★★★---》" + e.getMessage());
            e.printStackTrace();
        }
    }
}

最终效果
在这里插入图片描述


版权声明:本文为fen_dou_shao_nian原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/fen_dou_shao_nian/article/details/118943000