@@ -106,18 +106,48 @@ public static boolean isTerminated(ExecutorService pool) {
106106 }
107107 }
108108
109+ /**
110+ * Shutdown the {@link ExecutorService} and wait for 60 seconds for the threads to complete. More
111+ * detail on the waiting can be found in {@link #awaitTermination(ExecutorService)}.
112+ *
113+ * @param pool The ExecutorService to shutdown and wait on
114+ */
109115 public static void shutdownAndAwaitTermination (ExecutorService pool ) {
110116 if (pool == null ) return ;
111117 pool .shutdown (); // Disable new tasks from being submitted
112118 awaitTermination (pool );
113119 }
114120
121+ /**
122+ * Shutdown the {@link ExecutorService} and wait forever for the threads to complete. More detail
123+ * on the waiting can be found in {@link #awaitTerminationForever(ExecutorService)}.
124+ *
125+ * <p>This should likely not be used in {@code close()} methods, as we want to timebound when
126+ * shutting down. However, sometimes {@link ExecutorService}s are used to submit a list of tasks
127+ * and awaiting termination is akin to waiting on the list of {@link Future}s to complete. In that
128+ * case, this method should be used as there is no inherent time bound to waiting on those tasks
129+ * to complete.
130+ *
131+ * @param pool The ExecutorService to shutdown and wait on
132+ */
133+ public static void shutdownAndAwaitTerminationForever (ExecutorService pool ) {
134+ if (pool == null ) return ;
135+ pool .shutdown (); // Disable new tasks from being submitted
136+ awaitTerminationForever (pool );
137+ }
138+
115139 public static void shutdownNowAndAwaitTermination (ExecutorService pool ) {
116140 if (pool == null ) return ;
117141 pool .shutdownNow (); // Disable new tasks from being submitted; interrupt existing tasks
118142 awaitTermination (pool );
119143 }
120144
145+ /**
146+ * Await the termination of an {@link ExecutorService} for a default of 60 seconds, then force
147+ * shutdown the remaining threads and wait another 60 seconds.
148+ *
149+ * @param pool the ExecutorService to wait on
150+ */
121151 public static void awaitTermination (ExecutorService pool ) {
122152 awaitTermination (pool , 60 , TimeUnit .SECONDS );
123153 }
@@ -143,6 +173,27 @@ static void awaitTermination(ExecutorService pool, long timeout, TimeUnit unit)
143173 }
144174 }
145175
176+ /**
177+ * Await the termination of an {@link ExecutorService} until all threads are complete, or until we
178+ * are interrupted, at which point the {@link ExecutorService} will be interrupted as well.
179+ *
180+ * @param pool the ExecutorService to wait on
181+ */
182+ public static void awaitTerminationForever (ExecutorService pool ) {
183+ boolean shutdown = false ;
184+ try {
185+ while (!shutdown ) {
186+ // Wait a while for existing tasks to terminate
187+ shutdown = pool .awaitTermination (60 , TimeUnit .SECONDS );
188+ }
189+ } catch (InterruptedException e ) {
190+ // Force cancel if current thread also interrupted
191+ pool .shutdownNow ();
192+ // Preserve interrupt status
193+ Thread .currentThread ().interrupt ();
194+ }
195+ }
196+
146197 /** See {@link java.util.concurrent.Executors#newFixedThreadPool(int, ThreadFactory)} */
147198 public static ExecutorService newMDCAwareFixedThreadPool (
148199 int nThreads , ThreadFactory threadFactory ) {
0 commit comments