首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SimpleAsyncTaskExecutor只触发8个线程

SimpleAsyncTaskExecutor只触发8个线程
EN

Stack Overflow用户
提问于 2019-09-19 14:35:43
回答 3查看 1.9K关注 0票数 2

我试图通过使用默认的SimpleAsyncTaskExecutor来理解Spring中@异步的行为(在这里,我没有明确地定义任何Executor )。根据SimpleAsyncTaskExecutor的文档,“默认情况下,并发线程的数量是无限的”。但是在运行下面的示例代码时,我所能看到的只有8个线程被激活,剩下的任务正在等待一个新线程来执行它们。我知道可以通过自定义执行器来防止这种情况,在这种情况下,可以定义线程池的大小。但是我想知道我对SimpleAsyncTaskExecutor的理解是否正确,或者我的代码有些地方不正确。

主班

代码语言:javascript
复制
@SpringBootApplication
@EnableAsync
public class MainRunner {

    private static final Logger LOGGER = LoggerFactory.getLogger(MainRunner.class);

    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...");

    }
}

MyService类

代码语言:javascript
复制
@Service
public class MyService {

    private static final Logger LOGGER = LoggerFactory.getLogger(MyService.class);

    @Async
    public void doSomething(String userName) {
        LOGGER.info(Thread.currentThread().getName() + ", "
                + Thread.currentThread().getId() + ", NAME: " + userName + " STARTING...");
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 1000000; j++) {
                int res = i + j;
            }
        }
        LOGGER.info(Thread.currentThread().getName() + ", "
                + Thread.currentThread().getId() + ", NAME: " + userName + " COMPLETE...");
    }
}

我希望看到所有50个任务都已启动,它们不会等待线程准备处理它们。但是,上面的代码会导致提交的前8个任务开始,其余的任务正在等待正在运行的任务完成,以便被捕获和执行。

代码语言:javascript
复制
2019-09-19 09:33:06.560  INFO 17376 --- [           main] sample.MainRunner                        : Starting the submission of tasks...
2019-09-19 09:33:06.564  INFO 17376 --- [           main] sample.MainRunner                        : Finished submission of tasks...
2019-09-19 09:33:06.566  INFO 17376 --- [         task-8] sample.MyService                         : task-8, 45, NAME: Number8 STARTING...
2019-09-19 09:33:06.566  INFO 17376 --- [         task-1] sample.MyService                         : task-1, 38, NAME: Number1 STARTING...
2019-09-19 09:33:06.566  INFO 17376 --- [         task-7] sample.MyService                         : task-7, 44, NAME: Number7 STARTING...
2019-09-19 09:33:06.567  INFO 17376 --- [         task-4] sample.MyService                         : task-4, 41, NAME: Number4 STARTING...
2019-09-19 09:33:06.566  INFO 17376 --- [         task-6] sample.MyService                         : task-6, 43, NAME: Number6 STARTING...
2019-09-19 09:33:06.567  INFO 17376 --- [         task-2] sample.MyService                         : task-2, 39, NAME: Number2 STARTING...
2019-09-19 09:33:06.567  INFO 17376 --- [         task-5] sample.MyService                         : task-5, 42, NAME: Number5 STARTING...
2019-09-19 09:33:06.567  INFO 17376 --- [         task-3] sample.MyService                         : task-3, 40, NAME: Number3 STARTING...

它等待前8个任务完成,然后执行其余的任务。我对SimpleAsyncTaskExecutor的理解是错的吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-09-19 16:54:35

您的代码没有使用SimpleAsyncTaskExecutor。

简单地使用@EnableAsync

启用Spring的异步方法执行能力,类似于Spring的XML命名空间中的功能。

Spring不创建基于该注释的SimpleAsyncTaskExecutor。查看日志输出:

2019年-09-19 12:45:43.475 INFO 19660 --主o.s.s.concurrent.ThreadPoolTaskExecutor :初始化ExecutorService 'applicationTaskExecutor‘

看起来,Spring正在创建它,它看起来是一个默认的ThreadPoolTaskExecutor,它可能与您的机器上的核数有关联(不过,我并没有真正检查)。

如果您真的想要SimpleAsyncTaskExecutor,可以在您的配置中实现AsyncConfigurer接口

代码语言:javascript
复制
@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...");
  }
}
票数 4
EN

Stack Overflow用户

发布于 2019-09-19 15:45:36

是的,线程受到CPU 这里中可用内核的限制。

核心

核心通常是CPU的基本计算单元,它可以运行单个程序上下文(如果它支持硬件线程,如Intel CPU上的超线程,则可以运行多个程序上下文)。

CPU

CPU可以具有一个或多个核心,以便在给定时间执行任务。这些任务通常是操作系统计划的软件进程和线程。请注意,操作系统可能有许多线程要运行,,但是CPU只能在给定的时间运行X这样的任务,其中X=核数*每个核的硬件线程数,其余的必须等待操作系统来调度它们,不管是抢占当前正在运行的任务还是任何其他方式。

,如果有更多的线程,会发生什么?

假设您有X个线程,那么CPU调度程序将给每个X线程分配一些CPU时间。有些线程将并行运行(如果您有4个内核,那么4个线程将在任何时候并行运行,或者如果您在Intel CPU上有4个核心超线程,那么总共有8个线程将并行运行),剩下的线程将处于等待或运行中,concurrently.You可以使用此命令查找可用处理器的数量Runtime.getRuntime().availableProcessors()

票数 1
EN

Stack Overflow用户

发布于 2020-05-03 15:23:43

当未定义自定义异步TaskExecution配置时,Springboot将使用默认配置。

TaskExecutionAutoConfiguration的bean名为applicationTaskExecutor

在Springboot启动期间,您可以找到以下日志行:

代码语言:javascript
复制
INFO  org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.initialize - Initializing ExecutorService 'applicationTaskExecutor'

在构建此默认TaskExecution配置期间,Springboot将使用包含默认信任值的TaskExecutionProperties

在它里面,我们可以看到默认使用的coreSize是8

代码语言:javascript
复制
private int coreSize = 8;

当然,我们可以覆盖默认的异步TaskExecution配置和/或创建多个信任。

代码语言:javascript
复制
@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;
    }

}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58013472

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档