77import java .util .Iterator ;
88import java .util .List ;
99import java .util .ListIterator ;
10- import java .util .UUID ;
1110import java .util .concurrent .ExecutionException ;
1211import java .util .concurrent .ExecutorService ;
1312import java .util .concurrent .Future ;
2019/**
2120 * A form of {@link ArrayList} whose actions are managed through a {@link ScheduledExecutorService}.
2221 * <p>
23- * This style of list provides a reliable way to stop a list's iteration as quickly as possible -- especially in the
24- * event of an infinite loop. This is achievable by having the list's iterative actions run through an internal {@link
25- * ScheduledExecutorService} instance.
22+ * This style of list provides a reliable way to stop a list's iteration as quickly as possible -- especially in the event of an infinite
23+ * loop. This is achievable by having the list's iterative actions run through an internal {@link ScheduledExecutorService} instance.
2624 * <p>
27- * When the list's manager is {@link #shutdown() shut down}, the manager-related methods can no longer be used. However,
28- * the standard {@link List} methods can still be accessed as normal.
25+ * When the list's manager is {@link #shutdown() shut down}, the manager-related methods can no longer be used. However, the standard
26+ * {@link List} methods can still be accessed as normal.
2927 * <p>
3028 * <b>This form of list is not meant for quick actions -- it is <i>very slow</i>.</b> Besides that, it is fairly
3129 * useful. It provides:
@@ -51,7 +49,6 @@ public class ManagedList<E> implements List<E> {
5149
5250 private final ArrayList <E > list ;
5351 private ScheduledExecutorService listManager ;
54- private final UUID uuid = UUID .randomUUID ();
5552
5653 /**
5754 * A constructor matching {@link ArrayList#ArrayList()}.
@@ -84,8 +81,8 @@ public ManagedList(Collection<? extends E> collection) {
8481 }
8582
8683 /**
87- * {@link #shutdownNow() Shuts down} the list's manager, and creates a new one. If the manager was previously shut
88- * down, this is the recommended way to restore it.
84+ * {@link #shutdownNow() Shuts down} the list's manager, and creates a new one. If the manager was previously shut down, this is the
85+ * recommended way to restore it.
8986 */
9087 public List <Runnable > resetManager () {
9188 List <Runnable > remnants = shutdownNow ();
@@ -125,47 +122,61 @@ public boolean isTerminated() {
125122 * Runs the given action on the list immediately.
126123 *
127124 * @param action The action to run on the list.
128- * @throws IllegalStateException if an {@link InterruptedException} or {@link ExecutionException} is received. In
129- * the case of {@link InterruptedException}, it will be wrapped. With {@link
130- * ExecutionException}, its underlying exception will be wrapped.
125+ * @throws IllegalStateException if an {@link InterruptedException} or {@link ExecutionException} is received. In the case of
126+ * {@link InterruptedException}, it will be wrapped. With {@link ExecutionException}, its underlying
127+ * exception will be wrapped.
131128 * @see ExecutorService#submit(Runnable)
132129 */
133130 public void run (Consumer <ArrayList <E >> action ) {
131+ if (listManager .isShutdown () || listManager .isTerminated ()) {
132+ return ;
133+ }
134+
134135 try {
135- listManager .submit (() -> {
136- action .accept (list );
137- }).get ();
138- } catch (InterruptedException exception ) {
139- Thread .currentThread ().interrupt ();
136+ listManager .submit (() -> action .accept (list )).get ();
137+ } catch (RejectedExecutionException exception ) {
138+ if (listManager .isShutdown () || listManager .isTerminated ()) {
139+ return ;
140+ }
141+
140142 throw new IllegalStateException (exception );
141143 } catch (ExecutionException exception ) {
142144 throw new IllegalStateException (exception .getCause ());
145+ } catch (InterruptedException exception ) {
146+ throw new IllegalStateException (exception );
143147 }
144148 }
145149
146150 /**
147151 * Iterates over the given list immediately, where the given action is applied to each element of the list.
148152 *
149153 * @param action The action to run on the list's elements.
150- * @throws IllegalStateException if an {@link InterruptedException} or {@link ExecutionException} is received. In
151- * the case of {@link InterruptedException}, it will be wrapped. With {@link
152- * ExecutionException}, its underlying exception will be wrapped.
154+ * @throws IllegalStateException if an {@link InterruptedException} or {@link ExecutionException} is received. In the case of
155+ * {@link InterruptedException}, it will be wrapped. With {@link ExecutionException}, its underlying
156+ * exception will be wrapped.
153157 * @see ExecutorService#submit(Runnable)
154158 */
155159 public void iterate (Consumer <E > action ) {
160+ if (listManager .isShutdown () || listManager .isTerminated ()) {
161+ return ;
162+ }
163+
156164 try {
157- listManager .submit (
158- () -> {
159- for (E element : list ) {
160- action .accept (element );
161- }
162- }
163- ).get ();
164- } catch (InterruptedException exception ) {
165- Thread .currentThread ().interrupt ();
165+ listManager .submit (() -> {
166+ for (E element : list ) {
167+ action .accept (element );
168+ }
169+ }).get ();
170+ } catch (RejectedExecutionException exception ) {
171+ if (listManager .isShutdown () || listManager .isTerminated ()) {
172+ return ;
173+ }
174+
166175 throw new IllegalStateException (exception );
167176 } catch (ExecutionException exception ) {
168177 throw new IllegalStateException (exception .getCause ());
178+ } catch (InterruptedException exception ) {
179+ throw new IllegalStateException (exception );
169180 }
170181 }
171182
@@ -175,15 +186,23 @@ public void iterate(Consumer<E> action) {
175186 * @param action The action to run on the list.
176187 * @param delay The time from now to the task's delayed execution.
177188 * @param unit The time unit of the {@code delay} parameter.
178- * @return a {@link ScheduledFuture} representing pending completion of the task and whose {@link
179- * ScheduledFuture#get()} method will return {@code null} upon completion.
189+ * @return a {@link ScheduledFuture} representing pending completion of the task and whose {@link ScheduledFuture#get()} method will
190+ * return {@code null} upon completion.
180191 * @throws RejectedExecutionException if the task cannot be scheduled for execution
181192 * @throws NullPointerException if command or unit is null
182193 */
183194 public ScheduledFuture <?> schedule (Consumer <ArrayList <E >> action , long delay , TimeUnit unit ) {
184- return listManager .schedule (() -> {
185- action .accept (list );
186- }, delay , unit );
195+ ScheduledFuture <?> scheduledFuture = null ;
196+
197+ try {
198+ return listManager .schedule (() -> action .accept (list ), delay , unit );
199+ } catch (RejectedExecutionException exception ) {
200+ if (!listManager .isShutdown () && !listManager .isTerminated ()) {
201+ throw new IllegalStateException (exception .getCause ());
202+ }
203+ }
204+
205+ return scheduledFuture ;
187206 }
188207
189208 /**
@@ -192,22 +211,32 @@ public ScheduledFuture<?> schedule(Consumer<ArrayList<E>> action, long delay, Ti
192211 * @param action The action to run on the list's elements.
193212 * @param delay The time from now to the task's delayed execution.
194213 * @param unit The time unit of the {@code delay} parameter.
195- * @return a {@link ScheduledFuture} representing pending completion of the task and whose {@link
196- * ScheduledFuture#get()} method will return {@code null} upon completion.
214+ * @return a {@link ScheduledFuture} representing pending completion of the task and whose {@link ScheduledFuture#get()} method will
215+ * return {@code null} upon completion.
197216 * @throws RejectedExecutionException if the task cannot be scheduled for execution
198217 * @throws NullPointerException if command or unit is null
199218 * @see ScheduledExecutorService#schedule(Runnable, long, TimeUnit)
200219 */
201220 public ScheduledFuture <?> scheduleIterate (Consumer <E > action , long delay , TimeUnit unit ) {
202- return listManager .schedule (
221+ ScheduledFuture <?> scheduledFuture = null ;
222+
223+ try {
224+ return listManager .schedule (
203225 () -> {
204226 for (E element : list ) {
205227 action .accept (element );
206228 }
207229 },
208230 delay ,
209231 unit
210- );
232+ );
233+ } catch (RejectedExecutionException exception ) {
234+ if (!listManager .isShutdown () && !listManager .isTerminated ()) {
235+ throw new IllegalStateException (exception .getCause ());
236+ }
237+ }
238+
239+ return scheduledFuture ;
211240 }
212241
213242 /**
@@ -217,18 +246,25 @@ public ScheduledFuture<?> scheduleIterate(Consumer<E> action, long delay, TimeUn
217246 * @param initialDelay The time to delay first execution
218247 * @param period The period between successive executions
219248 * @param unit The time unit of the initialDelay and period parameters
220- * @return A {@link ScheduledFuture} representing pending completion of the series of repeated tasks. The future's
221- * {@link Future#get()} method will never return normally, and will throw an exception upon task cancellation or
222- * abnormal termination of a task execution.
249+ * @return A {@link ScheduledFuture} representing pending completion of the series of repeated tasks. The future's {@link Future#get()}
250+ * method will never return normally, and will throw an exception upon task cancellation or abnormal termination of a task execution.
223251 * @throws RejectedExecutionException if the task cannot be scheduled for execution
224252 * @throws NullPointerException if command or unit is null
225253 * @throws IllegalArgumentException if period less than or equal to zero
226254 * @see ScheduledExecutorService#scheduleAtFixedRate(Runnable, long, long, TimeUnit)
227255 */
228256 public ScheduledFuture <?> scheduleAtFixedRate (Consumer <ArrayList <E >> action , long initialDelay , long period , TimeUnit unit ) {
229- return listManager .scheduleAtFixedRate (() -> {
230- action .accept (list );
231- }, initialDelay , period , unit );
257+ ScheduledFuture <?> scheduledFuture = null ;
258+
259+ try {
260+ return listManager .scheduleAtFixedRate (() -> action .accept (list ), initialDelay , period , unit );
261+ } catch (RejectedExecutionException exception ) {
262+ if (!listManager .isShutdown () && !listManager .isTerminated ()) {
263+ throw new IllegalStateException (exception .getCause ());
264+ }
265+ }
266+
267+ return scheduledFuture ;
232268 }
233269
234270 /**
@@ -238,25 +274,33 @@ public ScheduledFuture<?> scheduleAtFixedRate(Consumer<ArrayList<E>> action, lon
238274 * @param initialDelay The time to delay first execution.
239275 * @param period The period between successive executions.
240276 * @param unit The time unit of the initialDelay and period parameters.
241- * @return A {@link ScheduledFuture} representing pending completion of the series of repeated tasks. The future's
242- * {@link Future#get()} method will never return normally, and will throw an exception upon task cancellation or
243- * abnormal termination of a task execution.
277+ * @return A {@link ScheduledFuture} representing pending completion of the series of repeated tasks. The future's {@link Future#get()}
278+ * method will never return normally, and will throw an exception upon task cancellation or abnormal termination of a task execution.
244279 * @throws RejectedExecutionException if the task cannot be scheduled for execution.
245280 * @throws NullPointerException if command or unit is null.
246281 * @throws IllegalArgumentException if period less than or equal to zero.
247282 * @see ScheduledExecutorService#scheduleAtFixedRate(Runnable, long, long, TimeUnit)
248283 */
249284 public ScheduledFuture <?> scheduledIterateAtFixedRate (Consumer <E > action , long initialDelay , long period , TimeUnit unit ) {
250- return listManager .scheduleAtFixedRate (
251- () -> {
285+ ScheduledFuture <?> scheduledFuture = null ;
286+
287+ try {
288+ scheduledFuture = listManager .scheduleAtFixedRate (() -> {
252289 for (E element : list ) {
253290 action .accept (element );
254291 }
255292 },
256293 initialDelay ,
257294 period ,
258295 unit
259- );
296+ );
297+ } catch (RejectedExecutionException exception ) {
298+ if (!listManager .isShutdown () && !listManager .isTerminated ()) {
299+ throw new IllegalStateException (exception .getCause ());
300+ }
301+ }
302+
303+ return scheduledFuture ;
260304 }
261305
262306 /**
@@ -266,18 +310,25 @@ public ScheduledFuture<?> scheduledIterateAtFixedRate(Consumer<E> action, long i
266310 * @param initialDelay The time to delay first execution.
267311 * @param delay The delay between the termination of one execution and the commencement of the next.
268312 * @param unit The time unit of the initialDelay and delay parameters.
269- * @return a {@link ScheduledFuture} representing pending completion of the series of repeated tasks. The future's
270- * {@link Future#get()} method will never return normally, and will throw an exception upon task cancellation or
271- * abnormal termination of a task execution.
313+ * @return a {@link ScheduledFuture} representing pending completion of the series of repeated tasks. The future's {@link Future#get()}
314+ * method will never return normally, and will throw an exception upon task cancellation or abnormal termination of a task execution.
272315 * @throws RejectedExecutionException if the task cannot be scheduled for execution.
273316 * @throws NullPointerException if command or unit is null.
274317 * @throws IllegalArgumentException if delay less than or equal to zero.
275318 * @see ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)
276319 */
277320 public ScheduledFuture <?> scheduleWithFixedDelay (Consumer <ArrayList <E >> action , long initialDelay , long delay , TimeUnit unit ) {
278- return listManager .scheduleWithFixedDelay (() -> {
279- action .accept (list );
280- }, initialDelay , delay , unit );
321+ ScheduledFuture <?> scheduledFuture = null ;
322+
323+ try {
324+ scheduledFuture = listManager .scheduleWithFixedDelay (() -> action .accept (list ), initialDelay , delay , unit );
325+ } catch (RejectedExecutionException exception ) {
326+ if (!listManager .isShutdown () && !listManager .isTerminated ()) {
327+ throw new IllegalStateException (exception .getCause ());
328+ }
329+ }
330+
331+ return scheduledFuture ;
281332 }
282333
283334
@@ -288,16 +339,18 @@ public ScheduledFuture<?> scheduleWithFixedDelay(Consumer<ArrayList<E>> action,
288339 * @param initialDelay The time to delay first execution.
289340 * @param delay The delay between the termination of one execution and the commencement of the next.
290341 * @param unit The time unit of the initialDelay and delay parameters.
291- * @return a {@link ScheduledFuture} representing pending completion of the series of repeated tasks. The future's
292- * {@link Future#get()} method will never return normally, and will throw an exception upon task cancellation or
293- * abnormal termination of a task execution.
342+ * @return a {@link ScheduledFuture} representing pending completion of the series of repeated tasks. The future's {@link Future#get()}
343+ * method will never return normally, and will throw an exception upon task cancellation or abnormal termination of a task execution.
294344 * @throws RejectedExecutionException if the task cannot be scheduled for execution.
295345 * @throws NullPointerException if command or unit is null.
296346 * @throws IllegalArgumentException if delay less than or equal to zero.
297347 * @see ScheduledExecutorService#scheduleWithFixedDelay(Runnable, long, long, TimeUnit)
298348 */
299349 public ScheduledFuture <?> scheduledIterateWithFixedDelay (Consumer <E > action , long initialDelay , long delay , TimeUnit unit ) {
300- return listManager .scheduleWithFixedDelay (
350+ ScheduledFuture <?> scheduledFuture = null ;
351+
352+ try {
353+ scheduledFuture = listManager .scheduleWithFixedDelay (
301354 () -> {
302355 for (E element : list ) {
303356 action .accept (element );
@@ -306,7 +359,14 @@ public ScheduledFuture<?> scheduledIterateWithFixedDelay(Consumer<E> action, lon
306359 initialDelay ,
307360 delay ,
308361 unit
309- );
362+ );
363+ } catch (RejectedExecutionException exception ) {
364+ if (!listManager .isShutdown () && !listManager .isTerminated ()) {
365+ throw new IllegalStateException (exception .getCause ());
366+ }
367+ }
368+
369+ return scheduledFuture ;
310370 }
311371
312372 @ Override
0 commit comments