SpringBoot定时任务

注解方式

单线程

1、@EnableScheduling

在启动类添加注解

@SpringBootApplication
@EnableScheduling
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

2、@Scheduled

在定时执行的方法之上添加注解(类上需要有@Component注解)

@Component
public class Task1 {
    @Scheduled(cron ="*/1 * * * * ?")
    public void sayWord() {
        System.out.println("world");
    }
}

多线程

1、@EnableAsync+@EnableScheduling

在启动类添加注解

@SpringBootApplication
@EnableScheduling
@EnableAsync        // 开启多线程
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

2、@Async+@Scheduled

在定时执行的方法之上添加注解(类上需要有@Component注解)

@Component
public class Task1 {
    @Async
    @Scheduled(cron ="*/1 * * * * ?")
    public void sayWord() {
        System.out.println("world");
    }
}

@Scheduled参数

cron

语法格式:"秒域 分域 时域 日域 月域 周域 年域"(一般是六个或七个字段)

取值范围

域名可取值可取符号(仅列部分常用)
秒域0~59的整数* - , /
分域0~59的整数* - , /
时域0~23的整数* - , /
日域1~31的整数* - , / ? L
月域1~12的整数或JAN~DEC* - , /
周域1~7的整数或SUN~SAT* - , / ? L #
年域1970~2099的整数* - , /

在线生成corn表达式网址:在线Cron表达式生成器

fixedDelay

指定两次任务执行的时间间隔(毫秒),前一个任务结束与下一个任务开始的间隔

如:@Scheduled(fixedDelay = 5*1000 ),表示第一个任务执行结束,开始计时,过5秒后,开始第二次执行。

fixedRate

指定两次任务执行的时间间隔(毫秒),前一个任务开始与下一个任务开始的间隔。

如:@Scheduled(fixedRate= 5*1000 ),表示第一个任务开始执行,开始计时,过5秒后,开始第二次执行。

initialDelay

第一次延迟执行的时间

如:@Scheduled(initialDelay=1000, fixedRate=5000) //第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次

动态定时任务

1、@EnableScheduling

在启动类必须加上@EnableScheduling注解

@SpringBootApplication
@EnableScheduling
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

2、SchedulingConfigurer

实现SchedulingConfigurer并重写configureTasks方法

@Component
@EnableScheduling
public class MyTask implements SchedulingConfigurer {
 
    @Autowired
    protected CronMapper cronMapper;
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(() -> process(),
                triggerContext -> {
                    String cron = cronMapper.getCron(1);
                    if (cron.isEmpty()) {
                        System.out.println("cron is null");
                    }
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                });
    }
	// 定时任务
    private void process() {
		//TODO
        System.out.println("执行动态定时任务:"+new Date(System.currentTimeMillis())); 
    }
}

TaskScheduler接口

任务调度接口 TaskScheduler,它提供了多种方法来调度将来某个时间点要运行的任务。

schedule(Runnable task, Trigger trigger);
指定一个触发器执行定时任务。可以使用CronTrigger来指定Cron表达式,执行定时任务。

schedule(Runnable task, Date startTime);
指定一个具体时间点执行定时任务,可以动态的指定时间,开启任务。只执行一次。

scheduleAtFixedRate(Runnable task, long period);
立即执行,循环任务,指定一个执行周期(毫秒计时)
不管上一个周期是否执行完,到时间下个周期就开始执行

scheduleAtFixedRate(Runnable task, Date startTime, long period);
指定时间开始执行,循环任务,指定一个间隔周期(毫秒计时)
不管上一个周期是否执行完,到时间下个周期就开始执行

scheduleWithFixedDelay(Runnable task, long delay);
立即执行,循环任务,指定一个间隔周期(毫秒计时)
上一个周期执行完,等待delay时间,下个周期开始执行

scheduleWithFixedDelay(Runnable task, Date startTime, long delay);
指定时间开始执行,循环任务,指定一个间隔周期(毫秒计时)
上一个周期执行完,等待delay时间,下个周期开始执行

TaskScheduler有4个实现类: ConcurrentTaskSchedulerDefaultManagedTaskScheduler、ThreadPoolTaskSchedulerTimerManagerTaskScheduler

ConcurrentTaskScheduler

以当前线程执行任务,单个线程方式执行定时任务,适用于简单场景。

示例:

ConcurrentTaskScheduler taskScheduler = new ConcurrentTaskScheduler();

// 执行一次
taskScheduler.execute(() -> log.info(Thread.currentThread().getName() + "执行一次"));

// 周期性执行
taskScheduler.schedule(() -> log.info(Thread.currentThread().getName() + "多次执行"), new CronTrigger("0/2 * * * * ?"));

DefaultManagedTaskScheduler

以当前线程执行任务,这是ConcurrentTaskScheduler的子类,添加了JNDI的支持。和ConcurrentTaskScheduler一样的用法,需要使用JNDI可以单独设置。

ThreadPoolTaskScheduler

提供线程池管理的调度器:多线程定时任务执行,实现了TaskExecutor接口,从而使的单一的实例可以尽可能快地异步执行。可以设置执行线程池数(默认一个线程)。

ThreadPoolTaskScheduler 的方法:

  • 使用前必须得先调用initialize()【初始化方法】
  • 有shutDown()方法,可以关闭线程池

setPoolSize 
 设置线程池大小,最小为1,默认情况下也为1; 
setErrorHandler 
 设置异常处理器。 
getScheduledThreadPoolExecutor 
 获取ScheduledExecutor,默认是ScheduledThreadPoolExecutor类型。
getActiveCount 
 获取当前活动的线程数 
execute 
 提交执行一次的任务 
submit\submitListenable 
 提交执行一次的任务,并且返回一个Future对象供判断任务状态使用。 

方法1:增加配置类

@Configuration
public class ScheduleConfig {
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(5);
        taskScheduler.initialize();
        return taskScheduler;
    }
}

 方法2:在执行类里运行下面代码

ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(6);
taskScheduler.initialize(); // 务必调用此方法来手动启动

 执行方法:

// 执行一次
taskScheduler.execute(new Runnable() {
	@Override
	public void run() {
		log.info(Thread.currentThread().getName() + "执行一次");
	}
});
// 周期性执行
taskScheduler.schedule((new Runnable() {
	@Override
	public void run() {
		log.info(Thread.currentThread().getName() + "多次执行");
	}
}), new CronTrigger("0/2 * * * * ?"));

TimerManagerTaskScheduler

同时继承CommonJ中的TimerManager接口。在使用CommonJ进行调度时使用。

停止

ScheduledFuture:通过cancle和读取isCancelled结果来退出

调用完成之后会返回一个scheduledFuture,这个就是当前的任务调度器,停止的时候需要找到这个调度器,用这个调用器来终止。

boolean cancelled = scheduledFuture.isCancelled(); // 用来判断是否已经取消
if(!cancelled ){
    scheduledFuture.cancel(true);// 用来将当前的任务取消
}

异常

1、No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet: In this case, use RequestContextListener or RequestContextFilter to e xpose the current request. 

没有找到与线程绑定的请求:你是指在实际的web请求之外引用请求属性,还是在最初接收请求的线程之外处理请求?如果你确实在web请求中操作,但仍然收到这个消息,那么你的代码可能在DispatcherServlet之外运行:在这种情况下,使用RequestContextListener或RequestContextFilter来暴露当前请求。

因为这个错误信息是与Spring框架相关的,通常发生在尝试在实际的web请求之外访问请求属性,或者在最初接收请求的线程之外处理请求时。如果你正在处理一个web请求但仍然收到这个错误信息,那么很可能是因为你的代码在DispatcherServlet之外运行。DispatcherServlet负责处理web请求并在Spring框架中管理请求的生命周期。

问题发生的位置:

((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest()

修改为

try{
   HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
}catch (IllegalStateException e){
  return null;
} 

 2、可以结合事务

@Scheduled(cron = "0 0/1 * * * ? ")
@Transactional(rollbackFor = Exception.class)
public void addDept() {
       。。。
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值