@@ -86,6 +86,8 @@ public abstract class ExecutorConfigurationSupport extends CustomizableThreadFac
8686	@ Nullable 
8787	private  ExecutorLifecycleDelegate  lifecycleDelegate ;
8888
89+ 	private  volatile  boolean  lateShutdown ;
90+ 
8991
9092	/** 
9193	 * Set the ThreadFactory to use for the ExecutorService's thread pool. 
@@ -127,8 +129,9 @@ public void setRejectedExecutionHandler(@Nullable RejectedExecutionHandler rejec
127129	 * <p>Default is {@code false} as of 6.1, triggering an early soft shutdown of 
128130	 * the executor and therefore rejecting any further task submissions. Switch this 
129131	 * to {@code true} in order to let other components submit tasks even during their 
130- 	 * own destruction callbacks, at the expense of a longer shutdown phase. 
131- 	 * This will usually go along with 
132+ 	 * own stop and destruction callbacks, at the expense of a longer shutdown phase. 
133+ 	 * The executor will not go through a coordinated lifecycle stop phase then 
134+ 	 * but rather only stop tasks on its own shutdown. This usually goes along with 
132135	 * {@link #setWaitForTasksToCompleteOnShutdown "waitForTasksToCompleteOnShutdown"}. 
133136	 * <p>This flag will only have effect when the executor is running in a Spring 
134137	 * application context and able to receive the {@link ContextClosedEvent}. 
@@ -144,9 +147,13 @@ public void setAcceptTasksAfterContextClose(boolean acceptTasksAfterContextClose
144147	/** 
145148	 * Set whether to wait for scheduled tasks to complete on shutdown, 
146149	 * not interrupting running tasks and executing all tasks in the queue. 
147- 	 * <p>Default is {@code false}, shutting down immediately through interrupting 
148- 	 * ongoing tasks and clearing the queue. Switch this flag to {@code true} if 
149- 	 * you prefer fully completed tasks at the expense of a longer shutdown phase. 
150+ 	 * <p>Default is {@code false}, with a coordinated lifecycle stop first (unless 
151+ 	 * {@link #setAcceptTasksAfterContextClose "acceptTasksAfterContextClose"} 
152+ 	 * has been set) and then an immediate shutdown through interrupting ongoing 
153+ 	 * tasks and clearing the queue. Switch this flag to {@code true} if you 
154+ 	 * prefer fully completed tasks at the expense of a longer shutdown phase. 
155+ 	 * The executor will not go through a coordinated lifecycle stop phase then 
156+ 	 * but rather only stop and wait for task completion on its own shutdown. 
150157	 * <p>Note that Spring's container shutdown continues while ongoing tasks 
151158	 * are being completed. If you want this executor to block and wait for the 
152159	 * termination of tasks before the rest of the container continues to shut 
@@ -374,7 +381,7 @@ public void start() {
374381	 */ 
375382	@ Override 
376383	public  void  stop () {
377- 		if  (this .lifecycleDelegate  != null ) {
384+ 		if  (this .lifecycleDelegate  != null  && ! this . lateShutdown ) {
378385			this .lifecycleDelegate .stop ();
379386		}
380387	}
@@ -386,9 +393,12 @@ public void stop() {
386393	 */ 
387394	@ Override 
388395	public  void  stop (Runnable  callback ) {
389- 		if  (this .lifecycleDelegate  != null ) {
396+ 		if  (this .lifecycleDelegate  != null  && ! this . lateShutdown ) {
390397			this .lifecycleDelegate .stop (callback );
391398		}
399+ 		else  {
400+ 			callback .run ();
401+ 		}
392402	}
393403
394404	/** 
@@ -439,10 +449,16 @@ protected void afterExecute(Runnable task, @Nullable Throwable ex) {
439449	 */ 
440450	@ Override 
441451	public  void  onApplicationEvent (ContextClosedEvent  event ) {
442- 		if  (event .getApplicationContext () == this .applicationContext  && !this .acceptTasksAfterContextClose ) {
443- 			// Early shutdown signal: accept no further tasks, let existing tasks complete 
444- 			// before hitting the actual destruction step in the shutdown() method above. 
445- 			initiateShutdown ();
452+ 		if  (event .getApplicationContext () == this .applicationContext ) {
453+ 			if  (this .acceptTasksAfterContextClose  || this .waitForTasksToCompleteOnShutdown ) {
454+ 				// Late shutdown without early stop lifecycle. 
455+ 				this .lateShutdown  = true ;
456+ 			}
457+ 			else  {
458+ 				// Early shutdown signal: accept no further tasks, let existing tasks complete 
459+ 				// before hitting the actual destruction step in the shutdown() method above. 
460+ 				initiateShutdown ();
461+ 			}
446462		}
447463	}
448464
0 commit comments