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