社区网站7.6 任务执行和调度
JDK线程池(1)ExecutorService(2)ScheduledExecutorService Spring线程池(1)ThreadPoolTaskExecutor(2)ThreadPoolTaskSchedular 分布式定时任务Spring Quartz(官网http://www.quartz-schedular.org) JDK的线程池在分布式环境下有问题(因为它数据是存在
JDK线程池
(1)ExecutorService
(2)ScheduledExecutorService
Spring线程池
(1)ThreadPoolTaskExecutor
(2)ThreadPoolTaskSchedular
分布式定时任务
Spring Quartz(官网http://www.quartz-schedular.org)
JDK的线程池在分布式环境下有问题(因为它数据是存在内存的)
而Quartz用数据库来存数据,适用于分布式环境
新建ThreadPoolTests类,
private void sleep(long m){
try{
Thread.sleep(m);
}catch (InterruptedException e){
e.printStackTrace();
}
}
// 1.JDK普通线程池
@Test
public void testExecutorService(){
Runnable task = new Runnable() {
@Override
public void run() {
logger.debug("Hello ExecutorService");
}
};
for(int i=0;i<10;i++){
executorService.submit(task);
}
sleep(10000); //10秒,以免任务未执行完就结束了
}
// 2.JDK定时任务线程池
@Test
public void testScheduledExecutorService(){
Runnable task = new Runnable() { //先实现Runnable接口,得到一个线程体
@Override
public void run() {
logger.debug("Hello ScheduledExecutorService");
}
};
scheduledExecutorService.scheduleAtFixedRate(task, 10000, 1000, TimeUnit.MILLISECONDS); //延迟10000毫秒再开始执行
sleep(30000);
}
在application-properties里对Spring的线程池进行配置
# TaskExecutionProperties
spring.task.execution.pool.core-size=5
spring.task.execution.pool.max-size=15
spring.task.execution.pool.queue-capacity=100
# TaskSchedulingProperties
spring.task.scheduling.pool.size=5
新建ThreadPoolConfig类,
@Configuration
@EnableScheduling
@EnableAsync
public class ThreadPoolConfig {
}
在ThreadPoolTests类里,添加
//3.Spring普通线程池
@Test
public void testThreadPoolTaskExecutor(){
Runnable task = new Runnable() { //首先声明一个线程体
@Override
public void run() {
logger.debug("Hello ThreadPoolTaskExecutor");
}
};
for(int i=0;i<10;i++){
taskExecutor.submit(task);
}
sleep(10000); //阻塞一下
}
// 4.Spring定时任务线程池
@Test
public void testThreadPoolTaskScheduler(){
Runnable task = new Runnable() {
@Override
public void run() {
logger.debug("Hello ThreadPoolTaskScheduler");
}
};
Date startTime = new Date(System.currentTimeMillis()+10000); //当前时间再延迟10秒开始执行,这里不需要指定时间的单位,是因为spring这个方法已经内部默认以毫秒为单位
taskScheduler.scheduleAtFixedRate(task,startTime,1000);
sleep(30000); //阻塞30秒
}
在AlphaService类里,添加
private static final Logger logger = LoggerFactory.getLogger(AlphaService.class);
//让该方法在多线程环境下,被异步地调用
@Async
public void execute1(){ //和主线程并行执行
logger.debug("execute1");
}
在ThreadPoolTests类里添加
// 5.Spring普通线程池(简化)
@Test
public void testThreadPoolTaskExecutorSimple(){
for(int i=0;i<10;i++){
alphaService.execute1();
}
sleep(10000);
}
在AlphaService类里添加
@Scheduled(initialDelay = 10000,fixedRate = 1000)
public void execute2(){
logger.debug("execute2");
}
在ThreadPoolTests类里添加
// 5.Spring定时线程池(简化)
@Test
public void testThreadPoolTaskSchedulerSimple(){
// alphaService.execute2();
sleep(30000);
}
接下来学习quartz。需提前创建表。需要导包,搜索spring boot quartz,吧spring-boot-starter-quartz拷贝到pom.xml。
这个包里Scheduler是核心类(底层已经实例化好了),它里面有个Job接口(需要我们写),JobDetail是用来配置Job的。还有一个接口Trigger,规定这个Job什么时候运行,以什么样的频率运行。这些个配置只是在第一次启动的时候使用,以后就固定化到数据库里了。
qrtz_scheduler_state表里存的是定时器的信息,qrtz_locks是定时器的锁,当有多个定时器的时候,按照这个表来加锁。
新建quartz包,新建AlphaJob类
public class AlphaJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println(Thread.currentThread().getName()+":execute a quartz job.");
}
}
在config包下新建QuartzConfig类,
// FactoryBean可简化Bean的实例化过程(可以认为它底层封装了jobdetal详细的实例化过程)
// 1.通过FactoryBean封装Bean的实例化过程
// 2.将FactoryBean装配到Spring容器里
// 3.将FactoryBean注入给其他的Bean
// 4.该Bean得到的是FactoryBean所管理的对象实例
//配置JobDetail
@Bean
public JobDetailFactoryBean alphaJobDetail(){ //FactoryBean与spring IOC顶层的BeanFactory不同
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(AlphaJob.class);
factoryBean.setName("alphaJob");
factoryBean.setGroup("alphaJobGroup");
factoryBean.setDurability(true); //哪怕将来这个任务不再运行了,甚至它的Trigger都没有了,也要留在数据库(不删)
factoryBean.setRequestsRecovery(true);
return factoryBean;
}
// 配置Trigger(可用SimpleTriggerFactoryBean或复杂的ConTriggerFactoryBean(比如半夜做事,它里面有表达式))
@Bean
public SimpleTriggerFactoryBean alphaTrigger(JobDetail alphaJobDetail){ //JobDetail参数alphaJobDetail要与上面定义alphaJobDetail()的名字一致,以保证有多个实例的时候,优先选择名字一致的
SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
factoryBean.setJobDetail(alphaJobDetail);
factoryBean.setName("alphaTrigger");
factoryBean.setGroup("alphaTriggerGroup");
factoryBean.setRepeatInterval(3000); //每3秒
factoryBean.setJobDataMap(new JobDataMap()); //用来存储job的状态
return factoryBean;
}
在application-properties里添加
# 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.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
如果不想要这个定时任务了,可以手动删除数据库里相关数据,或者写一个测试类QuartzTests
@Autowired
private Scheduler scheduler;
@Test
public void testDeleteJob(){
try {
boolean result = scheduler.deleteJob(new JobKey("alphaJob","alphaJobGroup")); //通过name和group可以唯一地确定一个job
System.out.println(result);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
观察到数据库job和trigger的表清空了相关信息。还要注意,再次启动前,QuartzConfig的@Bean注释掉。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)