Merge branch '5.3.x'

This commit is contained in:
Stephane Nicoll 2021-11-24 14:02:57 +01:00
commit d5f36c7e2c
3 changed files with 75 additions and 3 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2018 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -75,6 +75,8 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
private boolean allowCoreThreadTimeOut = false; private boolean allowCoreThreadTimeOut = false;
private boolean prestartAllCoreThreads = false;
private int queueCapacity = Integer.MAX_VALUE; private int queueCapacity = Integer.MAX_VALUE;
private boolean exposeUnconfigurableExecutor = false; private boolean exposeUnconfigurableExecutor = false;
@ -118,6 +120,16 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut; this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
} }
/**
* Specify whether to start all core threads, causing them to idly wait for work.
* <p>Default is "false".
* @since 5.3.14
* @see java.util.concurrent.ThreadPoolExecutor#prestartAllCoreThreads
*/
public void setPrestartAllCoreThreads(boolean prestartAllCoreThreads) {
this.prestartAllCoreThreads = prestartAllCoreThreads;
}
/** /**
* Set the capacity for the ThreadPoolExecutor's BlockingQueue. * Set the capacity for the ThreadPoolExecutor's BlockingQueue.
* Default is {@code Integer.MAX_VALUE}. * Default is {@code Integer.MAX_VALUE}.
@ -153,6 +165,9 @@ public class ThreadPoolExecutorFactoryBean extends ExecutorConfigurationSupport
if (this.allowCoreThreadTimeOut) { if (this.allowCoreThreadTimeOut) {
executor.allowCoreThreadTimeOut(true); executor.allowCoreThreadTimeOut(true);
} }
if (this.prestartAllCoreThreads) {
executor.prestartAllCoreThreads();
}
// Wrap executor with an unconfigurable decorator. // Wrap executor with an unconfigurable decorator.
this.exposedExecutor = (this.exposeUnconfigurableExecutor ? this.exposedExecutor = (this.exposeUnconfigurableExecutor ?

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -94,6 +94,8 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
private boolean allowCoreThreadTimeOut = false; private boolean allowCoreThreadTimeOut = false;
private boolean prestartAllCoreThreads = false;
@Nullable @Nullable
private TaskDecorator taskDecorator; private TaskDecorator taskDecorator;
@ -197,6 +199,16 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
this.allowCoreThreadTimeOut = allowCoreThreadTimeOut; this.allowCoreThreadTimeOut = allowCoreThreadTimeOut;
} }
/**
* Specify whether to start all core threads, causing them to idly wait for work.
* <p>Default is "false".
* @since 5.3.14
* @see java.util.concurrent.ThreadPoolExecutor#prestartAllCoreThreads
*/
public void setPrestartAllCoreThreads(boolean prestartAllCoreThreads) {
this.prestartAllCoreThreads = prestartAllCoreThreads;
}
/** /**
* Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable} * Specify a custom {@link TaskDecorator} to be applied to any {@link Runnable}
* about to be executed. * about to be executed.
@ -256,6 +268,9 @@ public class ThreadPoolTaskExecutor extends ExecutorConfigurationSupport
if (this.allowCoreThreadTimeOut) { if (this.allowCoreThreadTimeOut) {
executor.allowCoreThreadTimeOut(true); executor.allowCoreThreadTimeOut(true);
} }
if (this.prestartAllCoreThreads) {
executor.prestartAllCoreThreads();
}
this.threadPoolExecutor = executor; this.threadPoolExecutor = executor;
return executor; return executor;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2021 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,8 +16,12 @@
package org.springframework.scheduling.concurrent; package org.springframework.scheduling.concurrent;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.FutureTask; 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.junit.jupiter.api.Test;
@ -25,10 +29,16 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.GenericApplicationContext;
import static org.assertj.core.api.Assertions.assertThat; 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;
/** /**
* Tests for {@link ThreadPoolExecutorFactoryBean}.
*
* @author Juergen Hoeller * @author Juergen Hoeller
*/ */
class ThreadPoolExecutorFactoryBeanTests { class ThreadPoolExecutorFactoryBeanTests {
@ -44,6 +54,27 @@ class ThreadPoolExecutorFactoryBeanTests {
context.close(); context.close();
} }
@Test
void executorWithDefaultSettingsDoesNotPrestartAllCoreThreads() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("taskExecutor", ThreadPoolExecutorFactoryBean.class, TestThreadPoolExecutorFactoryBean::new);
context.refresh();
ThreadPoolExecutor threadPoolExecutor = context.getBean(ThreadPoolExecutor.class);
verify(threadPoolExecutor, never()).prestartAllCoreThreads();
}
@Test
void executorWithPrestartAllCoreThreads() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("taskExecutor", ThreadPoolExecutorFactoryBean.class, () -> {
TestThreadPoolExecutorFactoryBean factoryBean = new TestThreadPoolExecutorFactoryBean();
factoryBean.setPrestartAllCoreThreads(true);
return factoryBean;
});
context.refresh();
ThreadPoolExecutor threadPoolExecutor = context.getBean(ThreadPoolExecutor.class);
verify(threadPoolExecutor).prestartAllCoreThreads();
}
@Configuration @Configuration
static class ExecutorConfig { static class ExecutorConfig {
@ -55,4 +86,15 @@ class ThreadPoolExecutorFactoryBeanTests {
} }
private static class TestThreadPoolExecutorFactoryBean extends ThreadPoolExecutorFactoryBean {
@Override
protected ThreadPoolExecutor createExecutor(
int corePoolSize, int maxPoolSize, int keepAliveSeconds, BlockingQueue<Runnable> queue,
ThreadFactory threadFactory, RejectedExecutionHandler rejectedExecutionHandler) {
return mock(ThreadPoolExecutor.class);
}
}
} }