定时任务

定时任务

  • Timer:jdk中自带的一个定时调度类,可以简单的实现按某一频度进行任务执行。提供的功能比较单一,无法实现复杂的调度任务。

  • ScheduledExecutorService:也是jdk自带的一个基于线程池设计的定时任务类。其每个调度任务都会分配到线程池中的一个线程执行,所以其任务是并发执行的,互不影响。

  • Spring Task:Spring提供的一个任务调度工具,支持注解和配置文件形式,支持Cron表达式,使用简单但功能强大。

  • Quartz:一款功能强大的任务调度器,可以实现较为复杂的调度功能,如每月一号执行、每天凌晨执行、每周五执行等等,还支持分布式调度,就是配置稍显复杂

Timer

<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.11</version>
</dependency>

实例

@GetMapping("/timer")
public string doTimer(){
    Timer timer = new Timer();
    timer.schedule(new TimerTaskLog(),1000,1000);
        //延迟一秒启动,每一秒执行一次
}
import com.hrzn.dao.app.ThermLogDAO;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.TimerTask;
public class TimerTaskLog extends TimerTask{
    @Autowired
    private ThermLogDAO thermLogDAO;
​
    @Override
    public void run() {
        long l = thermLogDAO.deleteLog();
        System.out.println("删除:"+l+"条");
    }
}

API

1、在特定时间执行任务,只执行一次

public void schedule(TimerTask task,Date time)

2、在特定时间之后执行任务,只执行一次

public void schedule(TimerTask task,long delay)

3、指定第一次执行的时间,然后按照间隔时间,重复执行

public void schedule(TimerTask task,Date firstTime,long period)

4、在特定延迟之后第一次执行,然后按照间隔时间,重复执行

public void schedule(TimerTask task,long delay,long period)

5、第一次执行之后,特定频率执行,与3同

public void scheduleAtFixedRate(TimerTask task,Date firstTime,long period)

6、在delay毫秒之后第一次执行,后按照特定频率执行

public void scheduleAtFixedRate(TimerTask task,long delay,long period)

参数:

  • delay: 延迟执行的毫秒数,即在delay毫秒之后第一次执行

  • period:重复执行的时间间隔

取消任务使用:timer.cancel()方法即可注销任务。

ScheduledExecutorService

ScheduledExecutorService可以说是Timer的替代类,因为Timer不支持多线程,任务是串行的,而且也不捕获异常,假设某个任务异常了,整个Timer就无法运行了。

实例

@GetMapping("/executor")
public String ScheduledExecutorService() {
    @Autowired
    private ThermLogDAO thermLogDAO;
    //
    ScheduledExecutorService service = Executors.newScheduledThreadPool(10);
    service.scheduleAtFixedRate(new Runnable() {
        
        @Override
        public void run() {
            //定时任务执行体
            long l = thermLogDAO.deleteLog();
            System.out.println("删除:"+l+"条");
            log.info("ScheduledExecutorService定时任务执行:" + new Date());                
        }
    }, 1, 1, TimeUnit.SECONDS);//首次延迟1秒,之后每1秒执行一次
    log.info("ScheduledExecutorService定时任务启动:" + new Date());    
    return "ScheduledExecutorService!";        
}

可同时设置多个任务,只需再次设置scheduleAtFixedRate即可 。

API

  • ScheduleAtFixedRate:

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);

参数说明:

  1. command:执行线程

  2. initialDelay:初始化延时

  3. period:两次开始执行最小间隔时间

  4. unit:计时单位

  • ScheduleWithFixedDelay:

public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);

参数说明:

  1. command:执行线程

  2. initialDelay:初始化延时

  3. delay:前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间)

  4. unit:计时单位

Sping Task

使用SpringTaskSpringBoot是很简单的,使用@Scheduled注解即可轻松搞定。

实例

0.启动类,加入@EnableScheduling让注解@Scheduled生效。

@SpringBootApplication
@ComponentScan(basePackages = {"com.hrzn.**"})
@EnableTransactionManagement
@EnableScheduling
public class HradminApplication {
    public static void main(String[] args) {
        SpringApplication.run(HradminApplication.class, args);
    }
}

1.编写一个调度类,系统启动后自动扫描,自动执行。

@Component
@Slf4j
public class LogTask {
    @Autowired
    private ThermLogDAO thermLogDAO;
​
    @Autowired
    FileSystemService fileSystemService;
​
    @Scheduled(fixedRate = 86400000)
    public void getLogTask(){
        try {
            boolean deleteLogFiles = fileSystemService.deleteLogFiles();
            if (deleteLogFiles){
                long deleteNumber = thermLogDAO.deleteLog();
                System.out.println("删除:"+deleteNumber+"条");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
​

使用都是简单的,现在我们来看看注解@Scheduled的参数意思:

  1. fixedRate:定义一个按一定频率执行的定时任务

  2. fixedDelay:定义一个按一定频率执行的定时任务,与上面不同的是,改属性可以配合initialDelay, 定义该任务延迟执行时间。

  3. cron:通过表达式来配置任务执行时间

     

基于接口(动态)

@Configuration
@EnableScheduling
@Slf4j
public class ScheduleConfig implements SchedulingConfigurer {
    @Autowired
    TuyaService tuyaService;
    @Autowired
    TuyaParam tuyaParam;
    
    @Autowired
    AppScheduleMapper appScheduleMapper;
    
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        String cron = "0 0/3 * * * ?";
        taskRegistrar.addTriggerTask(new Runnable() {
            //定时器业务代码
            @Override
            public void run() {
                //TODO 查询所有当前时间4分钟内日程
                Calendar calendar = Calendar.getInstance(Locale.CHINA);
                calendar.setTime(new Date());
                int week = calendar.get(Calendar.DAY_OF_WEEK);
                int hour = calendar.get(Calendar.HOUR_OF_DAY);
                int min = calendar.get(Calendar.MINUTE);
                if (week == 1){
                    week = 7;
                }else {
                    week = week -1;
                }
                int totalMin =((week - 1) * 24 + hour) * 60 + min;
                List<ScheduleTaskPO> scheduleTaskPOS = appScheduleMapper.taskSchedule(totalMin-4,totalMin+4);
                for (ScheduleTaskPO scheduleTaskPO : scheduleTaskPOS) {
                    sendTemp(scheduleTaskPO.getDeviceid(),scheduleTaskPO.getTemp());
                }
            }
        },new Trigger() {
            //定时器
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                return new CronTrigger(cron).nextExecutionTime(triggerContext);
            }
        });
    }
    }
}
​

 

Cron表达式详解

一个cron表达式有至少6个(也可能7个)有空格分隔的时间元素。

依次顺序如下表所示:

字段允许值允许的特殊字符
0~59, - * /
0~59, - * /
小时0~23, - * /
日期1-31, - * ? / L W C
月份112或者JANDEC, - * /
星期17或者SUNSAT, - * ? / L C #
年(可选)留空,1970~2099, - * /

简单举例:

  • 0/1 * * * * ?:每秒执行一次

  • 0 0 2 1 * ? : 表示在每月的1日的凌晨2点调整任务

  • 0 0 10,14,16 ? :每天上午10点,下午2点,4点

  • 0 0 12 * * ? : 每天中午12点触发

  • 0 15 10 ? * MON-FRI : 周一至周五的上午10:15触发

自定义线程池

0.编写配置类,同时启用@Async注解:

@Configuration
@EnableAsync
public class Config {
    /**
     * 配置线程池
     * @return
     */
    @Bean(name = "scheduledPoolTaskExecutor")
    public ThreadPoolTaskExecutor getAsyncThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(20);
        taskExecutor.setMaxPoolSize(200);
        taskExecutor.setQueueCapacity(25);
        taskExecutor.setKeepAliveSeconds(200);
        taskExecutor.setThreadNamePrefix("oKong-Scheduled-");
        // 线程池对拒绝任务(无线程可用)的处理策略,目前只支持AbortPolicy、CallerRunsPolicy;默认为后者
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //调度器shutdown被调用时等待当前被调度的任务完成
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
        //等待时长
        taskExecutor.setAwaitTerminationSeconds(60);
        taskExecutor.initialize();
        return taskExecutor;
    }
}

1.调度类上加入@Async

@Component
@Slf4j
public class ScheduledTask {
    /**
     * 自动扫描,启动时间点之后5秒执行一次
     */
    @Async("scheduledPoolTaskExecutor")
    @Scheduled(fixedRate=5000)
    public void getCurrentDate() {
        log.info("Scheduled定时任务执行:" + new Date());
    }
}

动态添加定时任务

使用注解的方式,无法实现动态的修改或者添加新的定时任务的,这个使用就需要使用编程的方式进行任务的更新操作了。可直接使用ThreadPoolTaskScheduler或者SchedulingConfigurer接口进行自定义定时任务创建。

ThreadPoolTaskScheduler

ThreadPoolTaskSchedulerSpringTask的核心实现类,该类提供了大量的重载方法进行任务调度。这里简单示例下,具体的大家自行搜索下,用的少不太了解呀。

0.创建一个ThreadPoolTaskScheduler类。

    @Bean("taskExecutor")
    public TaskScheduler taskExecutor() {
        ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        executor.setPoolSize(20);
        executor.setThreadNamePrefix("oKong-taskExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //调度器shutdown被调用时等待当前被调度的任务完成
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //等待时长
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }

1.编写一个控制类,动态设置定时任务:

    @Autowired
    TaskScheduler taskScheduler;
    
    @GetMapping("/poolTask")
    public String threadPoolTaskScheduler() {
        taskScheduler.schedule(new Runnable() {
            @Override
            public void run() {
                log.info("ThreadPoolTaskScheduler定时任务:" + new Date());
            }
        }, new CronTrigger("0/3 * * * * ?"));//每3秒执行一次
        return "ThreadPoolTaskScheduler!";
    }

SchedulingConfigurer

此类十个接口,直接实现其configurerTasks方法即可。

0.编写配置类:

@Configuration
@Slf4j
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setTaskScheduler(taskExecutor());
        taskRegistrar.getScheduler().schedule(new Runnable() {
            @Override
            public void run() {
                log.info("SchedulingConfigurer定时任务:" + new Date());
            }
        }, new CronTrigger("0/3 * * * * ?"));//每3秒执行一次
    }
​
    @Bean("taskExecutor")
    public TaskScheduler taskExecutor() {
        ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
        executor.setPoolSize(20);
        executor.setThreadNamePrefix("oKong-Executor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //调度器shutdown被调用时等待当前被调度的任务完成
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //等待时长
        executor.setAwaitTerminationSeconds(60);
        return executor;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值