一、使用TimerTaskch创建
1、重写TimerTask
TimerTask
的子类可以通过实现run()
方法来定义具体的任务逻辑。当定时任务被触发时,run()
方法会在后台线程中执行。
TimerTask
主要用于在指定的时间点或时间间隔执行某个任务。
以下是
TimerTask
的一些常见用途:
执行定时任务:你可以继承
TimerTask
并实现run()
方法来执行需要定时执行的任务,比如定期备份数据库、定时发送邮件等。定时调度任务:你可以使用
TimerTask
配合Timer
或ScheduledExecutorService
来实现任务的定时调度,例如每隔一段时间执行一次任务或者在特定的时间点执行任务。
重写run方法实现定时任务内容
@Component
public class MyTask extends TimerTask implements Serializable {
private final RequirementsDao requirementsDao;
private PersonSendOrderVO personSendOrderVO;
public MyTask(RequirementsDao requirementsDao) {
this.requirementsDao = requirementsDao;
}
public void setPersonSendOrderVO(PersonSendOrderVO personSendOrderVO) {
this.personSendOrderVO = personSendOrderVO;
}
private static final long serialVersionUID = 1L;
@Override
public void run() {
requirementsDao.deleteSendOrder(personSendOrderVO.getRequirementsInfoId());
System.out.println("定时任务执行完毕!");
}
}
private PersonSendOrderVO personSendOrderVO;即为定时任务执行所需要参数
RequirementsDao requirementsDao;dao层代码需要利用构造函数引入,不能使用依赖注入
2、封装定时任务工具类
@Component
public class ScheduledTaskUtil {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private TaskScheduler taskScheduler;
@Autowired
private RequirementsDao requirementsDao;
private final Map<Integer, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
public void create(PersonSendOrderVO personSendOrderVO){
long delay = 10000; // 延迟10s开始执行
MyTask task = new MyTask(requirementsDao);
task.setPersonSendOrderVO(personSendOrderVO);
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.opsForValue().set("task"+personSendOrderVO.getRequirementsInfoId(), task, delay, TimeUnit.MILLISECONDS);
// 使用TaskScheduler执行定时任务
System.out.println("定时任务已开启");
ScheduledFuture<?> scheduledFuture = taskScheduler.schedule(task, Instant.now().plusMillis(delay));
scheduledTasks.put(personSendOrderVO.getRequirementsInfoId(), scheduledFuture);
}
public void destroy(Integer requireId){
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
MyTask task = (MyTask) redisTemplate.opsForValue().get("task"+requireId);
ScheduledFuture<?> scheduledFuture = scheduledTasks.get(requireId);
if (task != null && scheduledFuture != null) {
scheduledFuture.cancel(false);
redisTemplate.delete("task"+requireId);
scheduledTasks.remove(requireId);
System.out.println("定时任务已取消");
}
}
}
使用redis用于保存task对象
在
ScheduledTaskUtil
类中,我们使用scheduledTasks
对象来保存每个定时任务的ScheduledFuture
对象。这样做的目的是为了在需要取消任务时,能够根据任务的唯一标识(requireId
)快速找到对应的ScheduledFuture
对象,并调用其cancel()
方法来取消任务。具体来说,在
create()
方法中,我们使用taskScheduler.schedule()
方法创建定时任务,并将返回的ScheduledFuture
对象保存到scheduledTasks
中。在
destroy()
方法中,我们根据传入的requireId
从scheduledTasks
中获取对应的ScheduledFuture
对象,并调用其cancel()
方法来取消任务。然后,我们再从scheduledTasks
中移除该任务的相关内容。通过使用
scheduledTasks
对象,我们可以有效地管理和取消定时任务。
二、使用 ScheduledExecutorService
创建
ScheduledExecutorService
相较于TimerTask
配合Timer
有以下优势:
线程安全性:
ScheduledExecutorService
是线程安全的,可以在多线程环境下使用,而TimerTask
和Timer
是非线程安全的。由于Timer
内部只有一个线程用于执行任务,如果一个任务执行时间过长,会影响其他任务的执行。灵活性:
ScheduledExecutorService
提供了更多的调度方式。除了支持延迟执行任务外,还可以按固定频率执行任务、在指定时间点执行任务等。而TimerTask
只能支持延迟执行任务。异常处理:
ScheduledExecutorService
可以捕获任务执行过程中的异常,避免异常导致整个任务被取消。而TimerTask
无法捕获任务执行过程中的异常,一旦出现异常,整个Timer
将会终止。取消任务:
ScheduledExecutorService
提供了cancel()
方法用于取消任务的执行,而TimerTask
需要通过cancel()
方法取消Timer
中的全部任务。这意味着,使用ScheduledExecutorService
可以针对单个任务进行取消,而不影响其他任务的执行。扩展性:
ScheduledExecutorService
是ExecutorService
接口的子接口,可以与其他ExecutorService
相结合使用,实现更复杂的任务调度逻辑。而TimerTask
和Timer
用法相对简单,不易扩展
@Component
public class Test {
@Autowired
private RequirementsDao requirementsDao;
private final ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
private final ConcurrentHashMap<String, ScheduledFuture<?>> scheduledTasks = new ConcurrentHashMap<>();
public void create(PersonSendOrderVO personSendOrderVO, long delay) {
String requireId = personSendOrderVO.getRequirementsInfoId().toString();
// Runnable task = () -> requirementsDao.deleteSendOrder(personSendOrderVO.getRequirementsInfoId());
Runnable task = () -> System.out.println("定时任务已执行");
ScheduledFuture<?> scheduledFuture = scheduledExecutorService.schedule(task, delay, TimeUnit.MILLISECONDS);
scheduledTasks.put(requireId, scheduledFuture);
System.out.println("定时任务已创建,requirementsInfoId:" + requireId);
}
public void destroy(Integer requirementsInfoId) {
String requireId = requirementsInfoId.toString();
ScheduledFuture<?> scheduledFuture = scheduledTasks.remove(requireId);
if (scheduledFuture != null) {
scheduledFuture.cancel(true);
System.out.println("定时任务已取消,requirementsInfoId:" + requireId);
}
}
}