73 |
|
* } |
74 |
|
* }}</pre> |
75 |
|
* |
76 |
< |
* The following method shuts down an {@code ExecutorService} in two phases, |
77 |
< |
* first by calling {@code shutdown} to reject incoming tasks, and then |
78 |
< |
* calling {@code shutdownNow}, if necessary, to cancel any lingering tasks: |
76 |
> |
* An {@code ExecutorService} may also be established and closed |
77 |
> |
* (shutdown, blocking until terminated) as follows; illustrating with |
78 |
> |
* a different {@code Executors} factory method: |
79 |
> |
* |
80 |
> |
* <pre> {@code |
81 |
> |
* try (ExecutorService e = Executors.newWorkStealingPool()) { |
82 |
> |
* // submit or execute many tasks with e ... |
83 |
> |
* }}</pre> |
84 |
> |
* |
85 |
> |
* Further customization is also possible. For example, the following |
86 |
> |
* method shuts down an {@code ExecutorService} in two phases, first |
87 |
> |
* by calling {@code shutdown} to reject incoming tasks, and then |
88 |
> |
* calling {@code shutdownNow}, if necessary, to cancel any lingering |
89 |
> |
* tasks: |
90 |
|
* |
91 |
|
* <pre> {@code |
92 |
|
* void shutdownAndAwaitTermination(ExecutorService pool) { |
117 |
|
* @since 1.5 |
118 |
|
* @author Doug Lea |
119 |
|
*/ |
120 |
< |
public interface ExecutorService extends Executor { |
120 |
> |
public interface ExecutorService extends Executor, AutoCloseable { |
121 |
|
|
122 |
|
/** |
123 |
|
* Initiates an orderly shutdown in which previously submitted |
350 |
|
<T> T invokeAny(Collection<? extends Callable<T>> tasks, |
351 |
|
long timeout, TimeUnit unit) |
352 |
|
throws InterruptedException, ExecutionException, TimeoutException; |
353 |
+ |
|
354 |
+ |
/** |
355 |
+ |
* Initiates an orderly shutdown in which previously submitted tasks are |
356 |
+ |
* executed, but no new tasks will be accepted. This method waits until all |
357 |
+ |
* tasks have completed execution and the executor has terminated. |
358 |
+ |
* |
359 |
+ |
* <p> If interrupted while waiting, this method stops all executing tasks as |
360 |
+ |
* if by invoking {@link #shutdownNow()}. It then continues to wait until all |
361 |
+ |
* actively executing tasks have completed. Tasks that were awaiting |
362 |
+ |
* execution are not executed. The interrupt status will be re-asserted |
363 |
+ |
* before this method returns. |
364 |
+ |
* |
365 |
+ |
* <p> If already terminated, invoking this method has no effect. |
366 |
+ |
* |
367 |
+ |
* @implSpec |
368 |
+ |
* The default implementation invokes {@code shutdown()} and waits for tasks |
369 |
+ |
* to complete execution with {@code awaitTermination}. |
370 |
+ |
* |
371 |
+ |
* @throws SecurityException if a security manager exists and |
372 |
+ |
* shutting down this ExecutorService may manipulate |
373 |
+ |
* threads that the caller is not permitted to modify |
374 |
+ |
* because it does not hold {@link |
375 |
+ |
* java.lang.RuntimePermission}{@code ("modifyThread")}, |
376 |
+ |
* or the security manager's {@code checkAccess} method |
377 |
+ |
* denies access. |
378 |
+ |
* @since 19 |
379 |
+ |
*/ |
380 |
+ |
@Override |
381 |
+ |
default void close() { |
382 |
+ |
boolean terminated = isTerminated(); |
383 |
+ |
if (!terminated) { |
384 |
+ |
shutdown(); |
385 |
+ |
boolean interrupted = false; |
386 |
+ |
while (!terminated) { |
387 |
+ |
try { |
388 |
+ |
terminated = awaitTermination(1L, TimeUnit.DAYS); |
389 |
+ |
} catch (InterruptedException e) { |
390 |
+ |
if (!interrupted) { |
391 |
+ |
shutdownNow(); |
392 |
+ |
interrupted = true; |
393 |
+ |
} |
394 |
+ |
} |
395 |
+ |
} |
396 |
+ |
if (interrupted) { |
397 |
+ |
Thread.currentThread().interrupt(); |
398 |
+ |
} |
399 |
+ |
} |
400 |
+ |
} |
401 |
|
} |