Java SimpleAsyncTaskExecutor仅激发8个线程

Java SimpleAsyncTaskExecutor仅激发8个线程,java,multithreading,spring-boot,asynchronous,Java,Multithreading,Spring Boot,Asynchronous,我试图通过使用默认的SimpleAsyncTaskExecutor(在这里我没有显式定义任何执行器bean)来理解Spring Boot中@Async的行为。根据SimpleAsyncTaskExecutor的文档,“默认情况下,并发线程的数量是无限的”。但是在运行下面的示例代码时,我所看到的是只有8个线程启动,其余的任务正在等待获得一个新线程来执行它们。我知道这可以通过自定义执行器来防止,我可以在其中定义线程池的大小。但是我想知道我对SimpleAsyncTaskExecutor的理解是否正确

我试图通过使用默认的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;
    }

}