默认使用的线程池
在开发中,会有许多开箱即用的异步工具,如 Spring 的 Async ,Java 8 新增的 CompletableFuture 等。而这些工具都有默认使用的线程池,如果不了解这些默认使用的线程池很容易会出现难以预估的问题。
Async
在 Spring 中,用 @Async 注解指定的方法,该方法被调用时会以异步的方式执行。而如果没有在 @Async 注解中指定线程池,就会使用默认的线程池。默认的线程池为 SimpleAsyncTaskExecutor 。
该线程池不会复用线程,每有一个新任务被提交,该线程池就会创建一个新的线程实例用于执行任务。下面为相关的代码:
protected void doExecute(Runnable task) {
Thread thread = (this.threadFactory != null ? this.threadFactory.newThread(task) : createThread(task));
thread.start();
}
而如果想要指定线程池,可以通过在 @Async 注解中的 value 参数中指定所要使用的线程池的 Bean Name 。另一种方法是是一个实现了 AsyncConfigurer 接口或是继承其默认适配器类 AsyncConfigurerSupport 的配置类,这样 @Async 注解的方法就会使用指定的自定义的线程池。
Scheduled
在 Spring 中,可以使用 @Scheduled 注解方法,使方法可以定时执行。而这个过程是异步的,使用线程池来执行。在默认的情况下,使用的线程池是 Executors.newSingleThreadExecutor ,是一个单线程线程池,即相关的定时任务将会串行执行。
可以实现一个实现了 SchedulingConfigurer 接口的配置类,设置自定义的定时任务执行线程池。
CompletableFuture
Java 8 新增的 CompletableFuture 可以简单的异步执行任务。
CompletableFuture.runAsync(() -> System.out.println("run..."));
方法可以传递一个线程池对象,这样的话在异步执行时所使用的就是调用方法所指定的线程池。但是没有传递线程池对象的话,默认使用的是 ForkJoinPool.commonPool() ,ForkJoinPool 的一个通用线程池。
可以通过配置系统属性 java.util.concurrent.ForkJoinPool.common.parallelism 大于 1 更换成另外一个默认线程池。
System.setProperty("java.util.concurrent.ForkJoinPool.common.parallelism", "8");
另外的一个默认线程池为:
static final class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) { new Thread(r).start(); }
}
关于 ForkJoinPool 通用线程池的参考:ForkJoinPool 的 commonPool 相关参数配置