1
1
/*
2
- * Copyright 2002-2012 the original author or authors.
2
+ * Copyright 2002-2013 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
20
20
import java .util .concurrent .RejectedExecutionHandler ;
21
21
import java .util .concurrent .ThreadFactory ;
22
22
import java .util .concurrent .ThreadPoolExecutor ;
23
+ import java .util .concurrent .TimeUnit ;
23
24
24
25
import org .apache .commons .logging .Log ;
25
26
import org .apache .commons .logging .LogFactory ;
@@ -54,6 +55,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
54
55
55
56
private boolean waitForTasksToCompleteOnShutdown = false ;
56
57
58
+ private int awaitTerminationSeconds = 0 ;
59
+
57
60
private String beanName ;
58
61
59
62
private ExecutorService executor ;
@@ -85,16 +88,51 @@ public void setRejectedExecutionHandler(RejectedExecutionHandler rejectedExecuti
85
88
}
86
89
87
90
/**
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.
91
102
* @see java.util.concurrent.ExecutorService#shutdown()
92
103
* @see java.util.concurrent.ExecutorService#shutdownNow()
93
104
*/
94
105
public void setWaitForTasksToCompleteOnShutdown (boolean waitForJobsToCompleteOnShutdown ) {
95
106
this .waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown ;
96
107
}
97
108
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
+
98
136
public void setBeanName (String name ) {
99
137
this .beanName = name ;
100
138
}
@@ -145,6 +183,8 @@ public void destroy() {
145
183
/**
146
184
* Perform a shutdown on the ThreadPoolExecutor.
147
185
* @see java.util.concurrent.ExecutorService#shutdown()
186
+ * @see java.util.concurrent.ExecutorService#shutdownNow()
187
+ * @see #awaitTerminationIfNecessary()
148
188
*/
149
189
public void shutdown () {
150
190
if (logger .isInfoEnabled ()) {
@@ -156,6 +196,31 @@ public void shutdown() {
156
196
else {
157
197
this .executor .shutdownNow ();
158
198
}
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
+ }
159
224
}
160
225
161
226
}
0 commit comments