springboot @EnableScheduling 启用多线程

2020-10-30 10:20:33 浏览数 (3)

现象

使用@EnableScheduling注解后,可以发现所有任务都排队执行,并且调度器线程名称都是“taskScheduler-1”

原因

默认配置使用单线程调度器

解决方案

配置线程池任务调度器

代码语言:javascript复制
@Bean
public TaskScheduler taskScheduler() {
    ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
    taskScheduler.setPoolSize(10);
    return taskScheduler;
}

源码分析

  • org.springframework.scheduling.annotation.EnableScheduling
代码语言:javascript复制
// 导入配置
@Import(SchedulingConfiguration.class)
  • org.springframework.scheduling.annotation.SchedulingConfiguration
代码语言:javascript复制
// 注册调度注解处理器
@Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
	return new ScheduledAnnotationBeanPostProcessor();
}
  • org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor
代码语言:javascript复制
// 为registrar注入调度器实例
private void finishRegistration() {
	if (this.scheduler != null) {
		this.registrar.setScheduler(this.scheduler);
	}

	if (this.beanFactory instanceof ListableBeanFactory) {
		Map<String, SchedulingConfigurer> beans =
				((ListableBeanFactory) this.beanFactory).getBeansOfType(SchedulingConfigurer.class);
		List<SchedulingConfigurer> configurers = new ArrayList<>(beans.values());
		AnnotationAwareOrderComparator.sort(configurers);
		for (SchedulingConfigurer configurer : configurers) {
			configurer.configureTasks(this.registrar);
		}
	}

	if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) {
		// 从beanFactory查找调度器实例注入
		Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type");
		try {
			// Search for TaskScheduler bean...
			this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, false));
		}
		catch (NoUniqueBeanDefinitionException ex) {
			logger.trace("Could not find unique TaskScheduler bean", ex);
			try {
				this.registrar.setTaskScheduler(resolveSchedulerBean(this.beanFactory, TaskScheduler.class, true));
			}
			catch (NoSuchBeanDefinitionException ex2) {
				if (logger.isInfoEnabled()) {
					logger.info("More than one TaskScheduler bean exists within the context, and "  
							"none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' "  
							"(possibly as an alias); or implement the SchedulingConfigurer interface and call "  
							"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: "  
							ex.getBeanNamesFound());
				}
			}
		}
		catch (NoSuchBeanDefinitionException ex) {
			logger.trace("Could not find default TaskScheduler bean", ex);
			// Search for ScheduledExecutorService bean next...
			try {
				this.registrar.setScheduler(resolveSchedulerBean(this.beanFactory, ScheduledExecutorService.class, false));
			}
			catch (NoUniqueBeanDefinitionException ex2) {
				logger.trace("Could not find unique ScheduledExecutorService bean", ex2);
				try {
					this.registrar.setScheduler(resolveSchedulerBean(this.beanFactory, ScheduledExecutorService.class, true));
				}
				catch (NoSuchBeanDefinitionException ex3) {
					if (logger.isInfoEnabled()) {
						logger.info("More than one ScheduledExecutorService bean exists within the context, and "  
								"none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' "  
								"(possibly as an alias); or implement the SchedulingConfigurer interface and call "  
								"ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: "  
								ex2.getBeanNamesFound());
					}
				}
			}
			catch (NoSuchBeanDefinitionException ex2) {
				logger.trace("Could not find default ScheduledExecutorService bean", ex2);
				// Giving up -> falling back to default scheduler within the registrar...
				logger.info("No TaskScheduler/ScheduledExecutorService bean found for scheduled processing");
			}
		}
	}

	this.registrar.afterPropertiesSet();
}
  • org.springframework.scheduling.config.ScheduledTaskRegistrar
代码语言:javascript复制
// 配置调度任务
protected void scheduleTasks() {
	// 如果没有任务调度器,则创建单线程调度器
	if (this.taskScheduler == null) {
		this.localExecutor = Executors.newSingleThreadScheduledExecutor();
		this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
	}
	if (this.triggerTasks != null) {
		for (TriggerTask task : this.triggerTasks) {
			addScheduledTask(scheduleTriggerTask(task));
		}
	}
	if (this.cronTasks != null) {
		for (CronTask task : this.cronTasks) {
			addScheduledTask(scheduleCronTask(task));
		}
	}
	if (this.fixedRateTasks != null) {
		for (IntervalTask task : this.fixedRateTasks) {
			addScheduledTask(scheduleFixedRateTask(task));
		}
	}
	if (this.fixedDelayTasks != null) {
		for (IntervalTask task : this.fixedDelayTasks) {
			addScheduledTask(scheduleFixedDelayTask(task));
		}
	}
}
  • java.util.concurrent.Executors
代码语言:javascript复制
// 创建线程池容量为1的调度器
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
 return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1));
}

0 人点赞