diff --git a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.java b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.java index e880489f80..26dcec6370 100644 --- a/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.java +++ b/spring-context/src/main/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBean.java @@ -73,12 +73,14 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport private int keepAliveSeconds = 60; - private boolean allowCoreThreadTimeOut = false; - private int queueCapacity = Integer.MAX_VALUE; + private boolean allowCoreThreadTimeOut = false; + private boolean exposeUnconfigurableExecutor = false; + private boolean prestartAllCoreThreads = false; + @Nullable private ExecutorService exposedExecutor; @@ -130,6 +132,17 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport this.queueCapacity = queueCapacity; } + /** + * Specify whether this FactoryBean should prestart all threads + * for the created executor. + *
Default is "false".
+ * Switch this flag to "true" to prestart the threads allocated for the current executor
+ * @see java.util.concurrent.ThreadPoolExecutor#prestartAllCoreThreads
+ */
+ public void setPrestartAllCoreThreads(boolean prestartAllCoreThreads) {
+ this.prestartAllCoreThreads = prestartAllCoreThreads;
+ }
+
/**
* Specify whether this FactoryBean should expose an unconfigurable
* decorator for the created executor.
@@ -154,6 +167,10 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
executor.allowCoreThreadTimeOut(true);
}
+ if (this.prestartAllCoreThreads) {
+ executor.prestartAllCoreThreads();
+ }
+
// Wrap executor with an unconfigurable decorator.
this.exposedExecutor = (this.exposeUnconfigurableExecutor ?
Executors.unconfigurableExecutorService(executor) : executor);
diff --git a/spring-context/src/test/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBeanTests.java b/spring-context/src/test/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBeanTests.java
index abba6cf168..c5731e3139 100644
--- a/spring-context/src/test/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBeanTests.java
+++ b/spring-context/src/test/java/org/springframework/scheduling/concurrent/ThreadPoolExecutorFactoryBeanTests.java
@@ -16,17 +16,25 @@
package org.springframework.scheduling.concurrent;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.FutureTask;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ThreadPoolExecutor;
import org.junit.jupiter.api.Test;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
/**
* @author Juergen Hoeller
@@ -44,6 +52,21 @@ class ThreadPoolExecutorFactoryBeanTests {
context.close();
}
+ @Test
+ public void executorWithPreStartedThreads() throws Exception {
+ ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ExecutorConfigWithPreStartedThreads.class);
+ ThreadPoolExecutor executor = context.getBean("childExecutor", ThreadPoolExecutor.class);
+
+ verify(executor).prestartAllCoreThreads();
+ }
+
+ @Test
+ public void executorWithNoPreStartedThreads() throws Exception {
+ ConfigurableApplicationContext context = new AnnotationConfigApplicationContext(ExecutorConfigWithNoPreStartedThreads.class);
+ ThreadPoolExecutor executor = context.getBean("childExecutor", ThreadPoolExecutor.class);
+
+ verify(executor, never()).prestartAllCoreThreads();
+ }
@Configuration
static class ExecutorConfig {
@@ -55,4 +78,45 @@ class ThreadPoolExecutorFactoryBeanTests {
}
+ @Configuration
+ public static class ExecutorConfigWithPreStartedThreads {
+
+ @Bean
+ public ThreadPoolExecutorFactoryBean executorChildFactory() {
+ ThreadPoolExecutorFactoryBeanMockingChild threadPoolExecutorFactoryBeanMockingChild = new ThreadPoolExecutorFactoryBeanMockingChild();
+ threadPoolExecutorFactoryBeanMockingChild.setPrestartAllCoreThreads(true);
+ return threadPoolExecutorFactoryBeanMockingChild;
+ }
+
+ @Bean
+ public ExecutorService childExecutor() {
+ return executorChildFactory().getObject();
+ }
+ }
+
+ @Configuration
+ public static class ExecutorConfigWithNoPreStartedThreads {
+
+ @Bean
+ public ThreadPoolExecutorFactoryBean executorChildFactory() {
+ return new ThreadPoolExecutorFactoryBeanMockingChild();
+ }
+
+ @Bean
+ public ExecutorService childExecutor() {
+ return executorChildFactory().getObject();
+ }
+ }
+
+ private static class ThreadPoolExecutorFactoryBeanMockingChild extends ThreadPoolExecutorFactoryBean {
+ @Override
+ protected ThreadPoolExecutor createExecutor(
+ int corePoolSize, int maxPoolSize, int keepAliveSeconds, BlockingQueue