定时任务
在服务器中可能会有定时任务,但是不知道分布式系统下次会访问哪一个服务器,所以服务器中的任务就是相同的,这样会导致浪费。使用Quartz可以解决这个问题。
JDK线程池
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = MyCommunityApplication.class)
public class ThreadPoolTest {private Logger logger = LoggerFactory.getLogger(ThreadPoolTest.class);// JDK's normal thread-poolprivate ExecutorService executorService = Executors.newFixedThreadPool(5);// JDK's thread pool that periodically executes tasksprivate ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);private void sleep(long m){try{Thread.sleep(m);} catch(InterruptedException e){e.printStackTrace();}}@Testpublic void testExecutorService() {Runnable task = new Runnable() {@Overridepublic void run() {logger.info("hello executor service");}};for(int i = 0; i < 10; i++) {executorService.submit(task);}sleep(10000);}@Testpublic void testScheduleExecutorService(){Runnable task = new Runnable() {@Overridepublic void run() {logger.info("hello executor service");}};// 初始时间间隔为10000ms,任务间隔为1000msfor(int i = 0; i < 10; i++) {scheduledExecutorService.scheduleAtFixedRate(task, 10000, 1000, TimeUnit.MILLISECONDS);}sleep(30000);}
}
Spring线程池
配置application.properties
# Spring thread pool
# TaskExecutionProperties
spring.task.execution.pool.core-size=5
spring.task.execution.pool.max-size=15
spring.task.execution.pool.queue-capacity=100
# TaskScheduleProperties
spring.task.scheduling.pool.size=5
Spring线程池默认不开启定时线程池,需要新建配置类手动开启:
@Configuration
@EnableScheduling // 允许定时线程池
@EnableAsync // 允许多线程执行
public class ThreadPoolConfig {}
基于注入
测试方法:
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = MyCommunityApplication.class)
public class ThreadPoolTest {private Logger logger = LoggerFactory.getLogger(ThreadPoolTest.class);// Spring's normal thread pool@Autowiredprivate ThreadPoolTaskExecutor taskExecutor;// Spring's thread pool that periodically executes tasks// 如果配置类不加@EnableScheduling会报错@Autowiredprivate ThreadPoolTaskScheduler taskScheduler;private void sleep(long m){try{Thread.sleep(m);} catch(InterruptedException e){e.printStackTrace();}}@Testpublic void testThreadPoolTaskExecutor(){Runnable task = new Runnable() {@Overridepublic void run() {logger.info("hello spring thread pool");}};for(int i = 0; i < 10; i++){taskExecutor.submit(task);}sleep(10000);}@Testpublic void testThreadPoolTaskScheduler(){Runnable task = new Runnable() {@Overridepublic void run() {logger.info("hello spring thread pool");}};Date start = new Date(System.currentTimeMillis() + 10000);
// for(int i = 0; i < 10; i++){taskScheduler.scheduleAtFixedRate(task, start, 1000);
// }sleep(10000);}
}
基于注解
@Service
public class AlphaService {// 此前已经在配置类上允许了异步及定时// @EnableScheduling // 允许定时线程池// @EnableAsync // 允许异步执行// 加上这个注解说明是异步的@Asyncpublic void execute1(){logger.info("hello");}// 加上这个注解说明是定时任务// 第一次延迟10s,之后每次间隔1s// @Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。@Scheduled(initialDelay = 10000, fixedRate = 1000)public void execute2(){logger.info("hello2");}
}
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = MyCommunityApplication.class)
public class ThreadPoolTest {private Logger logger = LoggerFactory.getLogger(ThreadPoolTest.class);// Spring's normal thread pool@Autowiredprivate ThreadPoolTaskExecutor taskExecutor;// Spring's thread pool that periodically executes tasks@Autowiredprivate ThreadPoolTaskScheduler taskScheduler;@Autowiredprivate AlphaService alphaService;@Testpublic void testThreadPoolTaskExecutorSimple(){for(int i=0; i< 10; ++ i){alphaService.execute1();}sleep(10000);}@Testpublic void testThreadPoolTaskExecutorSimple2(){// 此处不需要调用alphaService.execute2方法// 因为有Scheduled注解的方法在程序开始时会自动执行
// alphaService.execute2();sleep(30000);}
}
分布式定时任务
新建任务
参考链接
引入依赖包
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-quartz --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
<!-- <version>3.1.2</version>--></dependency>
配置Quartz
# QuartzProperties
spring.quartz.job-store-type=jdbc
spring.quartz.scheduler-name=communityScheduler
spring.quartz.properties.org.quartz.scheduler.instanceId=AUTO
#spring.quartz.properties.org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
spring.quartz.properties.org.quartz.jobStore.class=org.springframework.scheduling.quartz.LocalDataSourceJobStore
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
spring.quartz.properties.org.quartz.jobStore.isClustered=true
spring.quartz.properties.org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
spring.quartz.properties.org.quartz.threadPool.threadCount=5
定义Job类:
public class AlphaJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println(Thread.currentThread().getName() + ":execute a quartz job");}
}
定义Quartz的配置类,该配置类只执行一次便被存入数据库的几个表中
// this configuration just for the first execution, and then the configuration will be saved in the database
@Configuration
public class QuartzConfig {// `FactoryBean` simplify the instantiation process of `Bean`// 1.The instantiation process of `Bean` is encapsulated through `FactoryBean`// 2.Assemble `FactoryBean` into `Spring`'s container// 3.Inject `FactoryBean` into the other beans// 4.This bean can acquire the object instance of the bean managed by the `FactoryBean`// inject `JobDetailFactoryBean` into this class// config `JobDetail`@Beanpublic JobDetailFactoryBean alphaJobDetail() {JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();factoryBean.setJobClass(AlphaJob.class);factoryBean.setName("alphaJob");factoryBean.setGroup("alphaGroup");// this task will be stored permanently although there are no triggers existingfactoryBean.setDurability(true);// this task can be recovered after meeting some faultsfactoryBean.setRequestsRecovery(true);return factoryBean;}// the `JobDetail` used is the object instance in `JobDetailFactoryBean`// config `Trigger(SimpleTriggerFactoryBean, CronTriggerFactoryBean)`@Beanpublic SimpleTriggerFactoryBean alphaTrigger(JobDetail alphaJobDetail) {SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();factoryBean.setJobDetail(alphaJobDetail);factoryBean.setName("alphaTrigger");factoryBean.setGroup("alphaGroup");// the interval of the triggerfactoryBean.setRepeatInterval(3000);// use an object to store the status of the job, `JobDataMap()` is the default objectfactoryBean.setJobDataMap(new JobDataMap());return factoryBean;}
}
启动程序后,Job自动执行,可以看到任务相关的信息已经自动加入到了表中:
删除任务
@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = MyCommunityApplication.class)
public class QuartzTest {@Autowiredprivate Scheduler scheduler;@Testpublic void testDeleteJob(){try {boolean result = scheduler.deleteJobs(Collections.singletonList(new JobKey("alphaJob", "alphaGroup")));System.out.println(result);} catch (SchedulerException e) {throw new RuntimeException(e);}}
}
可以看到,数据库中已经没有了关于任务的记录