java - SimpleAsyncTaskExecutor 仅启动 8 个线程

标签 java multithreading spring-boot asynchronous

我试图通过使用默认的 SimpleAsyncTaskExecutor (其中我没有显式定义任何 Executor bean)来了解 Spring Boot 中 @Async 的行为。根据 SimpleAsyncTaskExecutor 的文档,“默认情况下,并发线程数是无限的”。但在运行下面的示例代码时,我只能看到只有 8 个线程被启动,其余任务正在等待新线程来执行它们。我知道可以通过自定义执行器来防止这种情况,我可以在其中定义线程池的大小。但我想知道我对 SimpleAsyncTaskExecutor 的理解是否正确,或者我的代码有问题。

主类

@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 类

@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 个提交的任务开始运行,其余的任务正在等待正在运行的任务完成才能被拾取并执行。

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的理解有误吗?

最佳答案

您的代码未使用 SimpleAsyncTaskExecutor。

使用@EnableAsync简单地说

Enables Spring's asynchronous method execution capability, similar to functionality found in Spring's XML namespace.

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

2019-09-19 12:45:43.475 INFO 19660 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'

Spring 似乎正在创建一个默认的 ThreadPoolTask​​Executor,它可能与您计算机上的内核数量相关(不过我并没有真正检查过)。

如果您确实想要 SimpleAsyncTaskExecutor,您可以在配置中实现 AsyncConfigurer 接口(interface)

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

关于java - SimpleAsyncTaskExecutor 仅启动 8 个线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58013472/

相关文章:

spring - 为什么 Spring 安全性基于用户名而不是用户 ID?

java - 编码对象列表而不影响现有列表

java - 异常 java.net.SocketException : Connection reset

vb.net - 将 AsyncCallback 与 BeginInvoke 结合使用时,为什么我会在回调方法中收到 "Cross-thread operation not valid exception"?

java - DocumentBuilderFactory 在 Java 5+ 中是线程安全的吗?

java - 如何在 Spring Boot 中配置 Redis 缓存?

java - @ControllerAdvice 和 @ExceptionHandler 没有被我的 RestController 触发

java - 如何将 Object[][] 与字符串进行比较(包含)并将其值添加到另一个 Object[][]

java - 带有 JSP 的 JDBC 连接字符串 SQL Server 导致 "Illegal escape character"错误

java - 尝试并行运行 2 个 AsyncTasks,但它们似乎相互阻塞