引子
在现代应用开发中,定时任务的高效执行至关重要。Spring 框架提供了强大的任务调度功能,使得定时任务的管理变得简单而高效。然而,随着应用复杂度的增加,单线程调度器可能无法满足需求。本文将探讨如何从单线程调度器转变为多线程调度器,以提高定时任务的并发性和效率
Spring 任务调度的默认行为
单线程调度器
默认情况下,Spring 的 @Scheduled 任务是在一个单线程的调度器中执行的。这意味着如果一个定时任务正在执行,其他定时任务必须等待当前任务完成才能开始执行。
示例代码
@Scheduled(cron = "0/5 * * * * *")
public void fassToPcs() {
if (lock.tryLock()) {
try {
Thread.sleep(31000);
log.info("定时任务执行了===========");
} catch (Exception e) {
log.error("同步fass数据异常:{}", e.getMessage());
} finally {
lock.unlock();
}
} else {
log.warn("没有获取到锁");
}
}
问题分析
- 单线程执行:默认情况下,Spring 使用 ConcurrentTaskScheduler,它默认使用一个单线程的调度器。
- 任务执行时间的影响:如果一个定时任务的执行时间超过了调度周期,下一个定时任务会等待当前任务完成后再开始执行。
- 锁的必要性:即使在单线程调度器中,锁仍然可以确保代码在访问共享资源时不会发生冲突。
启用多线程调度
启用异步支持
为了实现定时任务的多线程执行,可以通过以下步骤启用异步方法支持
1. 添加 @EnableAsync 注解
在 Spring Boot 应用的启动类或配置类上添加 @EnableAsync 注解,以启用异步方法的支持
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
@EnableAsync
public class SkyTakeOutApplication {
public static void main(String[] args) {
SpringApplication.run(SkyTakeOutApplication.class, args);
}
}
2. 在定时任务方法上添加 @Async 注解
在 fassToPcs 方法上添加 @Async 注解,使其在单独的线程中执行。
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.locks.ReentrantLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Component
public class ScheduledParseFileFromFassTest {
private static final Logger log = LoggerFactory.getLogger(ScheduledParseFileFromFassTest.class);
private final ReentrantLock lock = new ReentrantLock();
@Scheduled(cron = "0/5 * * * * *")
@Async
public void fassToPcs() {
if (lock.tryLock()) {
try {
Thread.sleep(31000);
log.info("定时任务执行了===========");
} catch (Exception e) {
log.error("同步fass数据异常:{}", e.getMessage());
} finally {
lock.unlock();
}
} else {
log.warn("没有获取到锁");
}
}
}
总结:
通过本文的介绍,我们了解了 Spring 任务调度的默认行为,并探讨了如何通过启用异步支持将单线程调度器转变为多线程调度器。具体步骤包括:
1.启用异步支持:在启动类或配置类上添加 @EnableAsync 注解。
2.标记异步方法:在定时任务方法上添加 @Async 注解,使其在单独的线程中执行。
3.锁的竞争:即使定时任务在单独的线程中执行,锁仍然可以确保在同一时间只有一个线程能够执行临界区代码。