@@ -92,6 +92,8 @@ public class SimpleAsyncTaskExecutor extends CustomizableThreadCreator
9292 @ Nullable
9393 private Set <Thread > activeThreads ;
9494
95+ private boolean cancelRemainingTasksOnClose = false ;
96+
9597 private boolean rejectTasksWhenLimitReached = false ;
9698
9799 private volatile boolean active = true ;
@@ -184,12 +186,33 @@ public void setTaskDecorator(TaskDecorator taskDecorator) {
184186 * @param timeout the timeout in milliseconds
185187 * @since 6.1
186188 * @see #close()
189+ * @see #setCancelRemainingTasksOnClose
187190 * @see org.springframework.scheduling.concurrent.ExecutorConfigurationSupport#setAwaitTerminationMillis
188191 */
189192 public void setTaskTerminationTimeout (long timeout ) {
190193 Assert .isTrue (timeout >= 0 , "Timeout value must be >=0" );
191194 this .taskTerminationTimeout = timeout ;
192- this .activeThreads = (timeout > 0 ? ConcurrentHashMap .newKeySet () : null );
195+ trackActiveThreadsIfNecessary ();
196+ }
197+
198+ /**
199+ * Specify whether to cancel remaining tasks on close: that is, whether to
200+ * interrupt any active threads at the time of the {@link #close()} call.
201+ * <p>The default is {@code false}, not tracking active threads at all or
202+ * just interrupting any remaining threads that still have not finished after
203+ * the specified {@link #setTaskTerminationTimeout taskTerminationTimeout}.
204+ * Switch this to {@code true} for immediate interruption on close, either in
205+ * combination with a subsequent termination timeout or without any waiting
206+ * at all, depending on whether a {@code taskTerminationTimeout} has been
207+ * specified as well.
208+ * @since 6.2.11
209+ * @see #close()
210+ * @see #setTaskTerminationTimeout
211+ * @see org.springframework.scheduling.concurrent.ExecutorConfigurationSupport#setWaitForTasksToCompleteOnShutdown
212+ */
213+ public void setCancelRemainingTasksOnClose (boolean cancelRemainingTasksOnClose ) {
214+ this .cancelRemainingTasksOnClose = cancelRemainingTasksOnClose ;
215+ trackActiveThreadsIfNecessary ();
193216 }
194217
195218 /**
@@ -249,6 +272,15 @@ public boolean isActive() {
249272 return this .active ;
250273 }
251274
275+ /**
276+ * Track active threads only when a task termination timeout has been
277+ * specified or interruption of remaining threads has been requested.
278+ */
279+ private void trackActiveThreadsIfNecessary () {
280+ this .activeThreads = (this .taskTerminationTimeout > 0 || this .cancelRemainingTasksOnClose ?
281+ ConcurrentHashMap .newKeySet () : null );
282+ }
283+
252284
253285 /**
254286 * Executes the given task, within a concurrency throttle
@@ -353,7 +385,7 @@ protected Thread newThread(Runnable task) {
353385 }
354386
355387 /**
356- * This close methods tracks the termination of active threads if a concrete
388+ * This close method tracks the termination of active threads if a concrete
357389 * {@link #setTaskTerminationTimeout task termination timeout} has been set.
358390 * Otherwise, it is not necessary to close this executor.
359391 * @since 6.1
@@ -364,17 +396,26 @@ public void close() {
364396 this .active = false ;
365397 Set <Thread > threads = this .activeThreads ;
366398 if (threads != null ) {
367- synchronized (threads ) {
368- try {
369- if (!threads .isEmpty ()) {
370- threads .wait (this .taskTerminationTimeout );
399+ if (this .cancelRemainingTasksOnClose ) {
400+ // Early interrupt for remaining tasks on close
401+ threads .forEach (Thread ::interrupt );
402+ }
403+ if (this .taskTerminationTimeout > 0 ) {
404+ synchronized (threads ) {
405+ try {
406+ if (!threads .isEmpty ()) {
407+ threads .wait (this .taskTerminationTimeout );
408+ }
409+ }
410+ catch (InterruptedException ex ) {
411+ Thread .currentThread ().interrupt ();
371412 }
372413 }
373- catch (InterruptedException ex ) {
374- Thread .currentThread ().interrupt ();
414+ if (!this .cancelRemainingTasksOnClose ) {
415+ // Late interrupt for remaining tasks after timeout
416+ threads .forEach (Thread ::interrupt );
375417 }
376418 }
377- threads .forEach (Thread ::interrupt );
378419 }
379420 }
380421 }
0 commit comments