Java SimpleAsyncTaskExecutor仅激发8个线程
我试图通过使用默认的SimpleAsyncTaskExecutor(在这里我没有显式定义任何执行器bean)来理解Spring Boot中@Async的行为。根据SimpleAsyncTaskExecutor的文档,“默认情况下,并发线程的数量是无限的”。但是在运行下面的示例代码时,我所看到的是只有8个线程启动,其余的任务正在等待获得一个新线程来执行它们。我知道这可以通过自定义执行器来防止,我可以在其中定义线程池的大小。但是我想知道我对SimpleAsyncTaskExecutor的理解是否正确,或者我的代码有什么地方不正确 主类Java SimpleAsyncTaskExecutor仅激发8个线程,java,multithreading,spring-boot,asynchronous,Java,Multithreading,Spring Boot,Asynchronous,我试图通过使用默认的SimpleAsyncTaskExecutor(在这里我没有显式定义任何执行器bean)来理解Spring Boot中@Async的行为。根据SimpleAsyncTaskExecutor的文档,“默认情况下,并发线程的数量是无限的”。但是在运行下面的示例代码时,我所看到的是只有8个线程启动,其余的任务正在等待获得一个新线程来执行它们。我知道这可以通过自定义执行器来防止,我可以在其中定义线程池的大小。但是我想知道我对SimpleAsyncTaskExecutor的理解是否正确
@springboot应用程序
@使能同步
公营班主任{
私有静态最终记录器Logger=LoggerFactory.getLogger(mainlunner.class);
公共静态void main(字符串[]args){
ApplicationContext ApplicationContext=SpringApplication.run(MainRunner.class);
MyService MyService=(MyService)applicationContext.getBean(“MyService”);
LOGGER.info(“开始提交任务…”);
对于(inti=1;iYes),线程受到CPU中可用内核的限制
核心
内核通常是CPU的基本计算单元——它可以运行单个程序上下文(如果它支持硬件线程,如英特尔CPU上的超线程,则可以运行多个程序上下文)
CPU
一个CPU可能有一个或多个内核在给定时间执行任务。这些任务通常是操作系统调度的软件进程和线程。请注意,操作系统可能有许多线程要运行,但CPU在给定时间只能运行X个这样的任务,其中X=内核数*每个内核的硬件线程数。其余的都会有等待操作系统调度它们,无论是通过抢占当前正在运行的任务还是任何其他方式
如果线程数更多,会发生什么情况?
假设您有X个线程,那么CPU调度程序将为这些X个线程中的每一个分配一定的CPU时间。一些线程将并行运行(如果您有4个内核,那么任何时候都有4个线程并行运行,或者如果您在英特尔CPU上有4个内核的超线程,那么总共有8个线程并行运行)剩余的线程将等待或同时运行。您可以使用此命令查找可用处理器的数量Runtime.getRuntime()。AvailableProcessor()
您的代码未使用SimpleAsynctAskeExecutor
简单使用
启用Spring的异步方法执行功能,类似于Spring的XML命名空间中的功能
Spring不会基于该注释创建SimpleAsyncTaskExecutor。查看日志输出:
2019-09-19 12:45:43.475信息19660---[main]o.s.s.concurrent.ThreadPoolTaskExecutor:初始化ExecutorService'applicationTaskExecutor'
Spring似乎正在创建一个默认的ThreadPoolTaskExecutor,它可能与您机器上的内核数量有关(不过我没有真正检查)
如果您确实需要SimpleAsyncTaskExecutor,可以在配置中实现AsyncConfigurer接口
@SpringBootApplication
@EnableAsync
public class MainRunner implements AsyncConfigurer {
private static final Logger LOGGER = (Logger) LoggerFactory.getLogger(MainRunner.class);
@Override
public Executor getAsyncExecutor() {
return new SimpleAsyncTaskExecutor();
}
public static void main(String[] args) {
ApplicationContext applicationContext = SpringApplication.run(MainRunner.class);
MyService myService = (MyService) applicationContext.getBean("myService");
LOGGER.info("Starting the submission of tasks...");
for (int i = 1; i <= 50; i++)
{
myService.doSomething("Number" + i);
}
LOGGER.info("Finished submission of tasks...");
}
}
@springboot应用程序
@使能同步
公共类MainRunner实现AsyncConfigurer{
私有静态最终记录器=(记录器)LoggerFactory.getLogger(MainRunner.class);
@凌驾
公共执行器getAsyncExecutor(){
返回新的SimpleAsyncTaskExecutor();
}
公共静态void main(字符串[]args){
ApplicationContext ApplicationContext=SpringApplication.run(MainRunner.class);
MyService MyService=(MyService)applicationContext.getBean(“MyService”);
LOGGER.info(“开始提交任务…”);
对于(int i=1;i,当没有定义自定义异步TaskExecution配置时,Springboot将使用默认配置。
使用bean名称applicationTaskExecutor
在Springboot启动期间,您可以找到以下日志行:
INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.initialize - Initializing ExecutorService 'applicationTaskExecutor'
在构建此默认TaskExecution配置期间,Springboot将使用包含默认配置值的
在它里面,我们可以看到默认使用的coreSize是8
private int coreSize = 8;
当然,我们可以覆盖默认的异步TaskExecution配置和/或创建多个配置
@Configuration
@EnableAsync
public class EnableAsyncConfig implements AsyncConfigurer {
@Bean
public Executor taskExecutor() {
// Async thread pool configuration
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(40);
executor.initialize();
return executor;
}
}
可能会查询您的CPU数量,为每个核心创建一个线程。这比拥有50个线程和上下文开关更有效。@sturcotte06所以“无限线程”的假设受到每个核心线程数量的限制?我不会假设线程池创建线程的策略。只要假设它已优化。如果问题(未使用所有CPU资源或上下文开关过多),然后您可以切换实现并查看是否获得更好的结果。50个线程通常太多了,除非您使用的是阻塞IO。谢谢。但是,使用自定义执行器bean,将核心池大小设置为100,如何改变这一点呢?因为使用执行器并设置较高的核心池大小,任务不会等待您选择p、 线程池是通过并行运行任务来获得优势的,如果你想并行运行更多的线程,你需要更多的cpu资源@IceMan
@Configuration
@EnableAsync
public class EnableAsyncConfig implements AsyncConfigurer {
@Bean
public Executor taskExecutor() {
// Async thread pool configuration
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(40);
executor.initialize();
return executor;
}
}