Skip to content

Commit 408c3fe

Browse files
committed
ensure managed list doesn't throw rejected execution exceptions if it does not need to
1 parent accd358 commit 408c3fe

File tree

1 file changed

+121
-61
lines changed

1 file changed

+121
-61
lines changed

src/main/java/tech/fastj/systems/collections/ManagedList.java

Lines changed: 121 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import java.util.Iterator;
88
import java.util.List;
99
import java.util.ListIterator;
10-
import java.util.UUID;
1110
import java.util.concurrent.ExecutionException;
1211
import java.util.concurrent.ExecutorService;
1312
import java.util.concurrent.Future;
@@ -20,12 +19,11 @@
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

Comments
 (0)