ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/AbstractExecutorService.java
Revision: 1.54
Committed: Fri Nov 27 17:41:59 2020 UTC (3 years, 5 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.53: +2 -2 lines
Log Message:
Incorporate snippets code improvements from Pavel Rappo

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package java.util.concurrent;
8
9 import static java.util.concurrent.TimeUnit.NANOSECONDS;
10
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Iterator;
14 import java.util.List;
15
16 /**
17 * Provides default implementations of {@link ExecutorService}
18 * execution methods. This class implements the {@code submit},
19 * {@code invokeAny} and {@code invokeAll} methods using a
20 * {@link RunnableFuture} returned by {@code newTaskFor}, which defaults
21 * to the {@link FutureTask} class provided in this package. For example,
22 * the implementation of {@code submit(Runnable)} creates an
23 * associated {@code RunnableFuture} that is executed and
24 * returned. Subclasses may override the {@code newTaskFor} methods
25 * to return {@code RunnableFuture} implementations other than
26 * {@code FutureTask}.
27 *
28 * <p><b>Extension example.</b> Here is a sketch of a class
29 * that customizes {@link ThreadPoolExecutor} to use
30 * a {@code CustomTask} class instead of the default {@code FutureTask}:
31 * <pre> {@code
32 * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
33 *
34 * static class CustomTask<V> implements RunnableFuture<V> { ... }
35 *
36 * protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
37 * return new CustomTask<V>(c);
38 * }
39 * protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) {
40 * return new CustomTask<V>(r, v);
41 * }
42 * // ... add constructors, etc.
43 * }}</pre>
44 *
45 * @since 1.5
46 * @author Doug Lea
47 */
48 public abstract class AbstractExecutorService implements ExecutorService {
49
50 /**
51 * Constructor for subclasses to call.
52 */
53 public AbstractExecutorService() {}
54
55 /**
56 * Returns a {@code RunnableFuture} for the given runnable and default
57 * value.
58 *
59 * @param runnable the runnable task being wrapped
60 * @param value the default value for the returned future
61 * @param <T> the type of the given value
62 * @return a {@code RunnableFuture} which, when run, will run the
63 * underlying runnable and which, as a {@code Future}, will yield
64 * the given value as its result and provide for cancellation of
65 * the underlying task
66 * @since 1.6
67 */
68 protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
69 return new FutureTask<T>(runnable, value);
70 }
71
72 /**
73 * Returns a {@code RunnableFuture} for the given callable task.
74 *
75 * @param callable the callable task being wrapped
76 * @param <T> the type of the callable's result
77 * @return a {@code RunnableFuture} which, when run, will call the
78 * underlying callable and which, as a {@code Future}, will yield
79 * the callable's result as its result and provide for
80 * cancellation of the underlying task
81 * @since 1.6
82 */
83 protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
84 return new FutureTask<T>(callable);
85 }
86
87 /**
88 * @throws RejectedExecutionException {@inheritDoc}
89 * @throws NullPointerException {@inheritDoc}
90 */
91 public Future<?> submit(Runnable task) {
92 if (task == null) throw new NullPointerException();
93 RunnableFuture<Void> ftask = newTaskFor(task, null);
94 execute(ftask);
95 return ftask;
96 }
97
98 /**
99 * @throws RejectedExecutionException {@inheritDoc}
100 * @throws NullPointerException {@inheritDoc}
101 */
102 public <T> Future<T> submit(Runnable task, T result) {
103 if (task == null) throw new NullPointerException();
104 RunnableFuture<T> ftask = newTaskFor(task, result);
105 execute(ftask);
106 return ftask;
107 }
108
109 /**
110 * @throws RejectedExecutionException {@inheritDoc}
111 * @throws NullPointerException {@inheritDoc}
112 */
113 public <T> Future<T> submit(Callable<T> task) {
114 if (task == null) throw new NullPointerException();
115 RunnableFuture<T> ftask = newTaskFor(task);
116 execute(ftask);
117 return ftask;
118 }
119
120 /**
121 * the main mechanics of invokeAny.
122 */
123 private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
124 boolean timed, long nanos)
125 throws InterruptedException, ExecutionException, TimeoutException {
126 if (tasks == null)
127 throw new NullPointerException();
128 int ntasks = tasks.size();
129 if (ntasks == 0)
130 throw new IllegalArgumentException();
131 ArrayList<Future<T>> futures = new ArrayList<>(ntasks);
132 ExecutorCompletionService<T> ecs =
133 new ExecutorCompletionService<T>(this);
134
135 // For efficiency, especially in executors with limited
136 // parallelism, check to see if previously submitted tasks are
137 // done before submitting more of them. This interleaving
138 // plus the exception mechanics account for messiness of main
139 // loop.
140
141 try {
142 // Record exceptions so that if we fail to obtain any
143 // result, we can throw the last exception we got.
144 ExecutionException ee = null;
145 final long deadline = timed ? System.nanoTime() + nanos : 0L;
146 Iterator<? extends Callable<T>> it = tasks.iterator();
147
148 // Start one task for sure; the rest incrementally
149 futures.add(ecs.submit(it.next()));
150 --ntasks;
151 int active = 1;
152
153 for (;;) {
154 Future<T> f = ecs.poll();
155 if (f == null) {
156 if (ntasks > 0) {
157 --ntasks;
158 futures.add(ecs.submit(it.next()));
159 ++active;
160 }
161 else if (active == 0)
162 break;
163 else if (timed) {
164 f = ecs.poll(nanos, NANOSECONDS);
165 if (f == null)
166 throw new TimeoutException();
167 nanos = deadline - System.nanoTime();
168 }
169 else
170 f = ecs.take();
171 }
172 if (f != null) {
173 --active;
174 try {
175 return f.get();
176 } catch (ExecutionException eex) {
177 ee = eex;
178 } catch (RuntimeException rex) {
179 ee = new ExecutionException(rex);
180 }
181 }
182 }
183
184 if (ee == null)
185 ee = new ExecutionException();
186 throw ee;
187
188 } finally {
189 cancelAll(futures);
190 }
191 }
192
193 public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
194 throws InterruptedException, ExecutionException {
195 try {
196 return doInvokeAny(tasks, false, 0);
197 } catch (TimeoutException cannotHappen) {
198 assert false;
199 return null;
200 }
201 }
202
203 public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
204 long timeout, TimeUnit unit)
205 throws InterruptedException, ExecutionException, TimeoutException {
206 return doInvokeAny(tasks, true, unit.toNanos(timeout));
207 }
208
209 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
210 throws InterruptedException {
211 if (tasks == null)
212 throw new NullPointerException();
213 ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
214 try {
215 for (Callable<T> t : tasks) {
216 RunnableFuture<T> f = newTaskFor(t);
217 futures.add(f);
218 execute(f);
219 }
220 for (int i = 0, size = futures.size(); i < size; i++) {
221 Future<T> f = futures.get(i);
222 if (!f.isDone()) {
223 try { f.get(); }
224 catch (CancellationException | ExecutionException ignore) {}
225 }
226 }
227 return futures;
228 } catch (Throwable t) {
229 cancelAll(futures);
230 throw t;
231 }
232 }
233
234 public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
235 long timeout, TimeUnit unit)
236 throws InterruptedException {
237 if (tasks == null)
238 throw new NullPointerException();
239 final long nanos = unit.toNanos(timeout);
240 final long deadline = System.nanoTime() + nanos;
241 ArrayList<Future<T>> futures = new ArrayList<>(tasks.size());
242 int j = 0;
243 timedOut: try {
244 for (Callable<T> t : tasks)
245 futures.add(newTaskFor(t));
246
247 final int size = futures.size();
248
249 // Interleave time checks and calls to execute in case
250 // executor doesn't have any/much parallelism.
251 for (int i = 0; i < size; i++) {
252 if (((i == 0) ? nanos : deadline - System.nanoTime()) <= 0L)
253 break timedOut;
254 execute((Runnable)futures.get(i));
255 }
256
257 for (; j < size; j++) {
258 Future<T> f = futures.get(j);
259 if (!f.isDone()) {
260 try { f.get(deadline - System.nanoTime(), NANOSECONDS); }
261 catch (CancellationException | ExecutionException ignore) {}
262 catch (TimeoutException timedOut) {
263 break timedOut;
264 }
265 }
266 }
267 return futures;
268 } catch (Throwable t) {
269 cancelAll(futures);
270 throw t;
271 }
272 // Timed out before all the tasks could be completed; cancel remaining
273 cancelAll(futures, j);
274 return futures;
275 }
276
277 private static <T> void cancelAll(ArrayList<Future<T>> futures) {
278 cancelAll(futures, 0);
279 }
280
281 /** Cancels all futures with index at least j. */
282 private static <T> void cancelAll(ArrayList<Future<T>> futures, int j) {
283 for (int size = futures.size(); j < size; j++)
284 futures.get(j).cancel(true);
285 }
286 }