Java实现定时任务的五种方式
第一种:使用死循环+线程等待
任务循环定时执行
public class Task {
public void startTask() {
Thread myThread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("每隔10秒执行一次:" + new Date());
try {
// 使用线程休眠来实现周期执行
Thread.sleep(1000 * 10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
myThread.start();
}
}
任务定时执行一次
public class Task {
public void startTask() {
Thread myThread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("线程启动时间:" + new Date());
try {
// 使用线程休眠来实现任务定时[延迟]执行
Thread.sleep(1000 * 10);
System.out.println("任务执行时间:" + new Date());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
myThread.start();
}
}
public class Task {
private ExecutorService executorService = Executors.newFixedThreadPool(16);
public void startTask(){
executorService.submit(new Runnable() {
@Override
public void run() {
try {
// 使用线程休眠来实现任务定时[延迟]执行
Thread.sleep(1000 * 10);
System.out.println("任务执行时间:" + new Date());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
}
}
第二种:Spring提供的@Scheduled注解
@Component
@EnableScheduling
public class MyTask{
//每10秒执行一次
/**
* 注解中的Cron表达式: {秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}
* 注意:日和周其中的一个必须为"?"
* 10/5 20 10 * * ? 每天10点20分第10秒以后,每5秒执行一次,到10点21分就不会执行了
*/
@Scheduled("0/10 * * * * ?")
public void startTask(){
System.out.println("每隔10秒执行一次:" + new Date());
}
}
Cron表达式详见:https://blog.csdn.net/weixin_38331049/article/details/121805463
第三种:使用Timer类
public class MyTask{
public void startTask() {
int count = 0;
Timer timer=new Timer();
TimerTask task=new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
count++;
System.out.println("每隔10秒执行一次:" + new Date());
if(count == 100) {
//关闭定时器
//System.out.println("定时器关闭=================================>");
timer.cancel();
return;
}
}
};
//参数:1、任务体 2、延时时间(可以指定执行日期)3、任务执行间隔时间
timer.schedule(task, 0, 1000*10);
}
}
第四种:使用ScheduledExecutorService
public class MyTask{
public void startTask(){
ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
executorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println("每隔10秒执行一次:" + new Date());
}
},10, TimeUnit.SECONDS);
}
}
第五种:使用Quartz
Quartz是一个开源的Java调度框架,可以用来实现在指定的时间或时间间隔触发任务执行的功能。它支持多种方式的作业调度,如基于日期、时间间隔和Cron表达式的调度。Quartz允许开发人员定义并执行大量的作业,并且在大规模部署时可以实现高可靠性、高可用性和可伸缩性。
Quartz四大核心内容:
job - 任务 - 你要做什么事?
JobDetail - - 数据 - 你要做什么事,需要什么数据?
Trigger - 触发器 - 你什么时候去做
Scheduler - 任务调度 - 你什么时候需要去做什么事?
使用案例一:
第一步:导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
第二步:创建一个任务类
//第一种方式:实现Job接口
//第一种方式:实现Job接口
package com.example.demo.quzrtz;
import com.example.demo.mapper.ProductMapper;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//通过getJobDataMap方法获取JobDetail所提供的数据
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
ProductMapper productMapper =(ProductMapper) jobDataMap.get("Mapper");
System.out.println("任务开始执行******");
}
}
//第二种方式:继承QuartzJobBean,重写executeInternal方法
public class MyJob extends QuartzJobBean{
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
//通过getJobDataMap方法获取JobDetail所提供的数据
JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
ProductMapper productMapper =(ProductMapper) jobDataMap.get("Mapper");
System.out.println("任务开始执行******");
}
}
第三步:配置JobDetail、Trigger、Schedule
package com.example.demo.quzrtz;
import com.example.demo.mapper.ProductMapper;
import org.quartz.*;
import org.quartz.impl.JobDetailImpl;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
@Configuration
public class QuartzConfig {
@Autowired
private ProductMapper productMapper;
@Bean(name = "MyJobDetaile1")
public JobDetail getJobDetail1() {
//将任务执行所需要的数据放入一个JobDataMap中,通过setJobDataMap方法将数据提供给任务
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("Mapper",productMapper);
//方式一使用JobDetailImpl
JobDetailImpl myJobDetail1 = new JobDetailImpl();
myJobDetail1.setJobDataMap(jobDataMap);
myJobDetail1.setName("MyJobDetail1");
//将JobDetail持久化到内存中
//由于JobDetail和Trigger目前还是单独两个个体,JobDetail创建完成后没有Trigger指向它会被删除
myJobDetail1.setDurability(true);
return myJobDetail1;
}
@Bean(name = "MyJobDetaile2")
public JobDetail getJobDetail2(){
//将任务执行所需要的数据放入一个JobDataMap中,通过setJobData方法将数据提供给任务
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("Mapper",productMapper);
//方式二使用JobBuilder
JobDetail myJobDetail2 = JobBuilder.newJob(MyJob.class)
.setJobData(jobDataMap)
.withIdentity("MyJobDetail2")
//将JobDetail持久化到内存中
//由于JobDetail和Trigger目前还是单独两个个体,JobDetail创建完成后没有Trigger指向它会被删除
.storeDurably(true)
.build();
return myJobDetail2;
}
/**
* 错误做法:将Trigger直接纳入容器
* 为什么不能将Trigger直接纳入容器?
* 如果将Trigger纳入容器,首先这个触发器需要在创建的时候就必须关联一个Job,其次该触发器会脱离Schedule在Spring容器启动后自动执行任务
*/
//@Bean(name = "MyTrigger")
public static Trigger getTrigger(){
SimpleTrigger myTrigger = TriggerBuilder.newTrigger()
.withIdentity("MyTrigger")
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(10).repeatForever())
//如果不是CronScheduleBuilder,并且没有指定startAt,任务和Trigger只要关联上(也就是说一旦调用了scheduleJob()方法)就会立马执行,默认采用startNow,也就是说当前时间执行一次,往后按照一定的周期执行任务
//如果不是CronScheduleBuilder,请指定startAt指定任务触发时间--何时触发
.startAt(new Date(System.currentTimeMillis()+5000))
.build();
return myTrigger;
}
@Bean
public Scheduler getSchedule(@Qualifier("MyJobDetaile1") JobDetail jobDetail) throws SchedulerException {
Trigger trigger = QuartzConfig .getTrigger()
//通过一个标准的SchedulerFactory获取一个Scheduler
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
//启动Schedule
scheduler.start();
//关联JobDetail和Trigger
scheduler.scheduleJob(jobDetail,trigger);
return scheduler;
}
}
注意:不能将Trigger直接纳入容器:如果将Trigger纳入容器,首先这个触发器需要在创建的时候就必须关联一个Job,其次该触发器会脱离Schedule在Spring容器启动后将任务自动执行
如果需要多次使用任务,任务完成后记得调用Schedule的deleteJob()方法解除JobDetail与之前的Trigger的关联
package com.example.demo.controller;
import com.example.demo.quartz.QuartzConfig;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.Date;
@RestController
@RequestMapping("/schedule")
public class ScheduleController {
@Autowired
private JobDetail jobDetail;
@Resource
private Scheduler MySchedule;
@RequestMapping("/start")
public String startSchedule() throws SchedulerException {
Trigger trigger = QuartzConfig.getTrigger();
//由于一个JobDetail只能关联一个Trigger解除上一次JobDetail与Trigger的关联
MySchedule.deleteJob(new JobKey("firstJob"));
MySchedule.scheduleJob(jobDetail,trigger);
return "任务启动成功"+new Date();
}
}
使用案例二
下载:https://download.csdn.net/download/qq_44861126/87695292