需求背景
最近在开发一个 邮箱系统
,主要的工作是前端负责把要发送邮件的用户邮箱、邮件内容写入数据库中,然后由系统中的发送任务异步把这些邮件发送出去,所以需要有一个可一直在内部循环执行的 异步
任务进行处理
技术方案
对于像 php
这种程序,只需要在后台用过命令方式启动一个定时任务或者是循环任务,就可以完成。对于像 java
这种程序,可直接使用他的多线程来完成:
1. 异步任务 @Async
@Service
public class AsyncTestDomain {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Async
public void task() {
try {
logger.info("[" + Thread.currentThread() + "] " + "任务开始");
// 模拟任务延时
Thread.sleep(3000);
logger.info("[" + Thread.currentThread() + "] " + "任务结束");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
}
@RestController
public class AsyncTestController {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
AsyncTestDomain asyncTestDomain;
@GetMapping("/task/async")
public String tetTask() {
logger.info("[" + Thread.currentThread() + "] " + "任务请求开始");
asyncTestDomain.task();
logger.info("[" + Thread.currentThread() + "] " + "任务请求结束");
return "ok";
}
}
前端调用 controller:
curl "http://localhost:9999/task/async"
通过这种方式,调用由前端通过 http 调用来控制,可以配合 crontab 进行。
2. 使用定时任务处理
单线程任务/单任务
@Component
public class TaskSchedulerServer {
Logger logger = LoggerFactory.getLogger(this.getClass());
Integer i = 0;
@Scheduled(fixedRate = 1000) // 每隔1秒执行一次
public void test() throws InterruptedException {
String s = "[" + Thread.currentThread() + "] " + CommonUtil.currentTimeMillisSec();
Thread.sleep(3000);
logger.info(s + " - " + CommonUtil.currentTimeMillisSec() + " " + ++i);
}
}
fixedRate:表示从任务开始的时间点起,每隔 5 秒执行一次。如果上一个任务还没完成,调度器会等待上一个任务结束,然后立即启动下一次任务。
fixedDelay:表示从任务完成的时间点起,延迟 5 秒再执行下一次任务。因此,如果一个任务执行花费 8 秒,下一次任务会在 8 秒后完成,然后再等 5 秒才会开始。
-
以上代码写好,springboot 运行起来后,
test()
就会自动运行而且,而且进行频率由fixedRate = 1000
控制; -
该任务由系统内部自动运行,不受外部环境影响/干涉
-
该任务是系统默认的任务模式,同时也属于单线程
多线程任务/多任务
配置:
@Configuration
@EnableScheduling
public class MultiThreadSchedulerConfig {
@Bean
public TaskScheduler multiThreadTaskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5);
scheduler.setThreadNamePrefix("MultiThreadScheduledTask-");
scheduler.initialize();
return scheduler;
}
}
使用:
如果没做其他处理,配置上面的多线程任务后,就默认生效,并且被使用了
同时使用单任务和多任务
单线程任务配置
@Configuration
@EnableScheduling
public class SchedulerConfig {
// 使用默认的单线程调度器
@Bean
public TaskScheduler defaultTaskScheduler() {
return new ConcurrentTaskScheduler(); // 单线程
}
}
多线程任务配置(见上)
使用
@Component
public class TaskSchedulerServer {
Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
TaskScheduler multiThreadTaskScheduler; // 注入多线程调度器;
Integer i = 0;
@Scheduled(fixedRate = 1000) // 每隔5秒执行一次
public void test() throws InterruptedException {
String s = "[" + Thread.currentThread() + "] " + CommonUtil.currentTimeMillisSec();
Thread.sleep(3000);
logger.info(s + " - " + CommonUtil.currentTimeMillisSec() + " " + ++i);
}
@Scheduled(fixedRate = 1000) // 每隔5秒执行一次
public void testMul() throws InterruptedException {
multiThreadTaskScheduler.scheduleAtFixedRate(()-> {
String s = "xxx[" + Thread.currentThread() + "] " + CommonUtil.currentTimeMillisSec();
logger.info(s + " - " + CommonUtil.currentTimeMillisSec() + " " + ++i);
}, 3000);
}
}