我试图通过使用默认的SimpleAsyncTaskExecutor来理解Spring中@异步的行为(在这里,我没有明确地定义任何Executor )。根据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的理解是错的吗?
发布于 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接口
@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...");
}
}发布于 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()。
发布于 2020-05-03 15:23:43
当未定义自定义异步TaskExecution配置时,Springboot将使用默认配置。
TaskExecutionAutoConfiguration的bean名为applicationTaskExecutor。
在Springboot启动期间,您可以找到以下日志行:
INFO org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.initialize - Initializing ExecutorService 'applicationTaskExecutor'在构建此默认TaskExecution配置期间,Springboot将使用包含默认信任值的TaskExecutionProperties。
在它里面,我们可以看到默认使用的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;
}
}https://stackoverflow.com/questions/58013472
复制相似问题