目录
1、基于Timer的定时任务
1.1介绍
1.2例子
1.3 前端请求
1.4 Controller 层
1.5 Service 层
1.6 结果
2、基于ScheduledExecutorService 的定时任务
2.1介绍
2.2 例子
2.3 Service 层
2.4 线程异常打印日志
2.5 运行结果
3、改进
3.1 线程池配置类
3.2 异步任务管理器
3.3 Service 层
3.4 运行结果
在JDK1.5之前使用的都是 Timer来完成定时任务, 特点是 单线程执行定时任务,因此存在以下问题:
使用 PostMan 发送POST 请求:localhost:8888/ruoyi/login ,请求参数: 用户名、密码、验证码、uuid
Controller 层接收请求,并调用 service 层处理请求
sercie 层启动两个定时任务
一个任务是 延迟3秒打印 用户名、密码、验证码和uuid 和线程名
另一个任务是 延迟1秒,每间隔1秒打印 当前时间 和线程名
package com.ruoyi.project.system.controller;
/**
* 登录验证
*
* @author ruoyi
*/
@RestController
public class SysLoginController {
@Resource
private SysLoginService loginService;
@PostMapping("/login")
public AjaxResult login(String username, String password, String code, String uuid) {
AjaxResult ajax = AjaxResult.success();
// 生成令牌
String token = loginService.login(username, password, code, uuid);
ajax.put(Constants.TOKEN, token);
return ajax;
}
}
ScheduledExecutorService 是 JDK1.5 出现的,是基于多线程的,线程之间互不影响
在 上一个例子中,我们发现 通过 timer 方式实现的定时器任务, 只要有一个任务出现异常而没有处理, 那么其他任务都会终止!!
本例子将解决这个问题。
前端请求 和 Controller层代码都一样的 这里就不重复了
package com.ruoyi.common.utils;
/**
* 线程相关工具类.
*
* @author ruoyi
*/
public class Threads {
private static final Logger logger = LoggerFactory.getLogger(Threads.class);
/**
* 打印线程异常信息
*/
public static void printException(Runnable r, Throwable t) {
if (t == null && r instanceof Future>) {
try {
Future> future = (Future>) r;
if (future.isDone()) {
future.get();
}
} catch (CancellationException ce) {
t = ce;
} catch (ExecutionException ee) {
t = ee.getCause();
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
if (t != null) {
logger.error(t.getMessage(), t);
}
}
}
上一个例子中 ScheduledExecutorService 对象是 new 出来的,这样的编码方式不好!
①、ScheduledExecutorService 对象应该交由 Spring 容器进行管理。
②、应该对 ScheduledExecutorService 进行封装,做成一个 单例的异步任务管理器
该配置类,向Spring容器中注入 ScheduledExecutorService 对象
package com.ruoyi.framework.config;
/**
* 线程池配置
*
* @author ruoyi
**/
@Configuration
public class ThreadPoolConfig {
// 核心线程池大小
private int corePoolSize = 50;
/**
* 执行周期性或定时任务
*/
@Bean(name = "scheduledExecutorService")
protected ScheduledExecutorService scheduledExecutorService() {
return new ScheduledThreadPoolExecutor(corePoolSize,
new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build()) {
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
Threads.printException(r, t);
}
};
}
}
package com.ruoyi.framework.manager;
/**
* 异步任务管理器
*
* @author ruoyi
*/
public class AsyncManager {
/**
* 操作延迟10毫秒
*/
private final int OPERATE_DELAY_TIME = 10;
/**
* 异步操作任务调度线程池
*/
private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
/**
* 单例模式
*/
private AsyncManager() {
}
private static AsyncManager me = new AsyncManager();
public static AsyncManager me() {
return me;
}
/**
* 执行任务
*
* @param task 任务
*/
public void execute(TimerTask task) {
executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
}
}
前端和Controller层代码不变