Skip to content

Commit 89db04e

Browse files
jhoellerunknown
authored andcommitted
Added "awaitTerminationSeconds" property to ThreadPoolTaskExecutor/ThreadPoolTaskScheduler
Issue: SPR-5387
1 parent 9c032d5 commit 89db04e

File tree

1 file changed

+69
-4
lines changed

1 file changed

+69
-4
lines changed

spring-context/src/main/java/org/springframework/scheduling/concurrent/ExecutorConfigurationSupport.java

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020
import java.util.concurrent.RejectedExecutionHandler;
2121
import java.util.concurrent.ThreadFactory;
2222
import java.util.concurrent.ThreadPoolExecutor;
23+
import java.util.concurrent.TimeUnit;
2324

2425
import org.apache.commons.logging.Log;
2526
import org.apache.commons.logging.LogFactory;
@@ -54,6 +55,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
5455

5556
private boolean waitForTasksToCompleteOnShutdown = false;
5657

58+
private int awaitTerminationSeconds = 0;
59+
5760
private String beanName;
5861

5962
private ExecutorService executor;
@@ -85,16 +88,51 @@ public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecuti
8588
}
8689

8790
/**
88-
* Set whether to wait for scheduled tasks to complete on shutdown.
89-
* <p>Default is "false". Switch this to "true" if you prefer
90-
* fully completed tasks at the expense of a longer shutdown phase.
91+
* Set whether to wait for scheduled tasks to complete on shutdown,
92+
* not interrupting running tasks and executing all tasks in the queue.
93+
* <p>Default is "false", shutting down immediately through interrupting
94+
* ongoing tasks and clearing the queue. Switch this flag to "true" if you
95+
* prefer fully completed tasks at the expense of a longer shutdown phase.
96+
* <p>Note that Spring's container shutdown continues while ongoing tasks
97+
* are being completed. If you want this executor to block and wait for the
98+
* termination of tasks before the rest of the container continues to shut
99+
* down - e.g. in order to keep up other resources that your tasks may need -,
100+
* set the {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"}
101+
* property instead of or in addition to this property.
91102
* @see java.util.concurrent.ExecutorService#shutdown()
92103
* @see java.util.concurrent.ExecutorService#shutdownNow()
93104
*/
94105
public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
95106
this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
96107
}
97108

109+
/**
110+
* Set the maximum number of seconds that this executor is supposed to block
111+
* on shutdown in order to wait for remaining tasks to complete their execution
112+
* before the rest of the container continues to shut down. This is particularly
113+
* useful if your remaining tasks are likely to need access to other resources
114+
* that are also managed by the container.
115+
* <p>By default, this executor won't wait for the termination of tasks at all.
116+
* It will either shut down immediately, interrupting ongoing tasks and clearing
117+
* the remaining task queue - or, if the
118+
* {@link #setWaitForTasksToCompleteOnShutdown "waitForTasksToCompleteOnShutdown"}
119+
* flag has been set to {@code true}, it will continue to fully execute all
120+
* ongoing tasks as well as all remaining tasks in the queue, in parallel to
121+
* the rest of the container shutting down.
122+
* <p>In either case, if you specify an await-termination period using this property,
123+
* this executor will wait for the given time (max) for the termination of tasks.
124+
* As a rule of thumb, specify a significantly higher timeout here if you set
125+
* "waitForTasksToCompleteOnShutdown" to {@code true} at the same time,
126+
* since all remaining tasks in the queue will still get executed - in contrast
127+
* to the default shutdown behavior where it's just about waiting for currently
128+
* executing tasks that aren't reacting to thread interruption.
129+
* @see java.util.concurrent.ExecutorService#shutdown()
130+
* @see java.util.concurrent.ExecutorService#awaitTermination
131+
*/
132+
public void setAwaitTerminationSeconds(int awaitTerminationSeconds) {
133+
this.awaitTerminationSeconds = awaitTerminationSeconds;
134+
}
135+
98136
public void setBeanName(String name) {
99137
this.beanName = name;
100138
}
@@ -145,6 +183,8 @@ public void destroy() {
145183
/**
146184
* Perform a shutdown on the ThreadPoolExecutor.
147185
* @see java.util.concurrent.ExecutorService#shutdown()
186+
* @see java.util.concurrent.ExecutorService#shutdownNow()
187+
* @see #awaitTerminationIfNecessary()
148188
*/
149189
public void shutdown() {
150190
if (logger.isInfoEnabled()) {
@@ -156,6 +196,31 @@ public void shutdown() {
156196
else {
157197
this.executor.shutdownNow();
158198
}
199+
awaitTerminationIfNecessary();
200+
}
201+
202+
/**
203+
* Wait for the executor to terminate, according to the value of the
204+
* {@link #setAwaitTerminationSeconds "awaitTerminationSeconds"} property.
205+
*/
206+
private void awaitTerminationIfNecessary() {
207+
if (this.awaitTerminationSeconds > 0) {
208+
try {
209+
if (!this.executor.awaitTermination(this.awaitTerminationSeconds, TimeUnit.SECONDS)) {
210+
if (logger.isWarnEnabled()) {
211+
logger.warn("Timed out while waiting for executor" +
212+
(this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate");
213+
}
214+
}
215+
}
216+
catch (InterruptedException ex) {
217+
if (logger.isWarnEnabled()) {
218+
logger.warn("Interrupted while waiting for executor" +
219+
(this.beanName != null ? " '" + this.beanName + "'" : "") + " to terminate");
220+
}
221+
Thread.currentThread().interrupt();
222+
}
223+
}
159224
}
160225

161226
}

0 commit comments

Comments
 (0)