|
Java example source code file (MoreExecutors.java)
The MoreExecutors.java Java example source code/* * Copyright (C) 2007 The Guava Authors * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.common.util.concurrent; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.annotations.Beta; import com.google.common.annotations.GwtCompatible; import com.google.common.annotations.GwtIncompatible; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.collect.Lists; import com.google.common.collect.Queues; import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.lang.reflect.InvocationTargetException; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Callable; import java.util.concurrent.Delayed; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.annotation.concurrent.GuardedBy; /** * Factory and utility methods for {@link java.util.concurrent.Executor}, {@link ExecutorService}, * and {@link ThreadFactory}. * * @author Eric Fellheimer * @author Kyle Littlefield * @author Justin Mahoney * @since 3.0 */ @GwtCompatible(emulated = true) public final class MoreExecutors { private MoreExecutors() {} /** * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their * completion. * * <p>This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. * * @param executor the executor to modify to make sure it exits when the application is finished * @param terminationTimeout how long to wait for the executor to finish before terminating the * JVM * @param timeUnit unit of time for the time parameter * @return an unmodifiable version of the input which will not hang the JVM */ @Beta @GwtIncompatible // TODO public static ExecutorService getExitingExecutorService( ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { return new Application().getExitingExecutorService(executor, terminationTimeout, timeUnit); } /** * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when * the application is complete. It does so by using daemon threads and adding a shutdown hook to * wait for their completion. * * <p>This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. * * @param executor the executor to modify to make sure it exits when the application is finished * @param terminationTimeout how long to wait for the executor to finish before terminating the * JVM * @param timeUnit unit of time for the time parameter * @return an unmodifiable version of the input which will not hang the JVM */ @Beta @GwtIncompatible // TODO public static ScheduledExecutorService getExitingScheduledExecutorService( ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { return new Application() .getExitingScheduledExecutorService(executor, terminationTimeout, timeUnit); } /** * Add a shutdown hook to wait for thread completion in the given {@link ExecutorService service}. * This is useful if the given service uses daemon threads, and we want to keep the JVM from * exiting immediately on shutdown, instead giving these daemon threads a chance to terminate * normally. * * @param service ExecutorService which uses daemon threads * @param terminationTimeout how long to wait for the executor to finish before terminating the * JVM * @param timeUnit unit of time for the time parameter */ @Beta @GwtIncompatible // TODO public static void addDelayedShutdownHook( ExecutorService service, long terminationTimeout, TimeUnit timeUnit) { new Application().addDelayedShutdownHook(service, terminationTimeout, timeUnit); } /** * Converts the given ThreadPoolExecutor into an ExecutorService that exits when the application * is complete. It does so by using daemon threads and adding a shutdown hook to wait for their * completion. * * <p>This method waits 120 seconds before continuing with JVM termination, even if the executor * has not finished its work. * * <p>This is mainly for fixed thread pools. See {@link Executors#newFixedThreadPool(int)}. * * @param executor the executor to modify to make sure it exits when the application is finished * @return an unmodifiable version of the input which will not hang the JVM */ @Beta @GwtIncompatible // concurrency public static ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) { return new Application().getExitingExecutorService(executor); } /** * Converts the given ScheduledThreadPoolExecutor into a ScheduledExecutorService that exits when * the application is complete. It does so by using daemon threads and adding a shutdown hook to * wait for their completion. * * <p>This method waits 120 seconds before continuing with JVM termination, even if the executor * has not finished its work. * * <p>This is mainly for fixed thread pools. See {@link Executors#newScheduledThreadPool(int)}. * * @param executor the executor to modify to make sure it exits when the application is finished * @return an unmodifiable version of the input which will not hang the JVM */ @Beta @GwtIncompatible // TODO public static ScheduledExecutorService getExitingScheduledExecutorService( ScheduledThreadPoolExecutor executor) { return new Application().getExitingScheduledExecutorService(executor); } /** Represents the current application to register shutdown hooks. */ @GwtIncompatible // TODO @VisibleForTesting static class Application { final ExecutorService getExitingExecutorService( ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { useDaemonThreadFactory(executor); ExecutorService service = Executors.unconfigurableExecutorService(executor); addDelayedShutdownHook(service, terminationTimeout, timeUnit); return service; } final ScheduledExecutorService getExitingScheduledExecutorService( ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) { useDaemonThreadFactory(executor); ScheduledExecutorService service = Executors.unconfigurableScheduledExecutorService(executor); addDelayedShutdownHook(service, terminationTimeout, timeUnit); return service; } final void addDelayedShutdownHook( final ExecutorService service, final long terminationTimeout, final TimeUnit timeUnit) { checkNotNull(service); checkNotNull(timeUnit); addShutdownHook( MoreExecutors.newThread( "DelayedShutdownHook-for-" + service, new Runnable() { @Override public void run() { try { // We'd like to log progress and failures that may arise in the // following code, but unfortunately the behavior of logging // is undefined in shutdown hooks. // This is because the logging code installs a shutdown hook of its // own. See Cleaner class inside {@link LogManager}. service.shutdown(); service.awaitTermination(terminationTimeout, timeUnit); } catch (InterruptedException ignored) { // We're shutting down anyway, so just ignore. } } })); } final ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) { return getExitingExecutorService(executor, 120, TimeUnit.SECONDS); } final ScheduledExecutorService getExitingScheduledExecutorService( ScheduledThreadPoolExecutor executor) { return getExitingScheduledExecutorService(executor, 120, TimeUnit.SECONDS); } @VisibleForTesting void addShutdownHook(Thread hook) { Runtime.getRuntime().addShutdownHook(hook); } } @GwtIncompatible // TODO private static void useDaemonThreadFactory(ThreadPoolExecutor executor) { executor.setThreadFactory( new ThreadFactoryBuilder() .setDaemon(true) .setThreadFactory(executor.getThreadFactory()) .build()); } /** * Creates an executor service that runs each task in the thread that invokes * {@code execute/submit}, as in {@link CallerRunsPolicy}. This applies both to individually * submitted tasks and to collections of tasks submitted via {@code invokeAll} or * {@code invokeAny}. In the latter case, tasks will run serially on the calling thread. Tasks are * run to completion before a {@code Future} is returned to the caller (unless the executor has * been shutdown). * * <p>Although all tasks are immediately executed in the thread that submitted the task, this * {@code ExecutorService} imposes a small locking overhead on each task submission in order to * implement shutdown and termination behavior. * * <p>The implementation deviates from the {@code ExecutorService} specification with regards to * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing * tasks. Second, the returned list will always be empty, as any submitted task is considered to * have started execution. This applies also to tasks given to {@code invokeAll} or * {@code invokeAny} which are pending serial execution, even the subset of the tasks that have * not yet started execution. It is unclear from the {@code ExecutorService} specification if * these should be included, and it's much easier to implement the interpretation that they not * be. Finally, a call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls * to {@code invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the * tasks may already have been executed. * * @since 10.0 (<a href="https://github.com/google/guava/wiki/Compatibility">mostly * source-compatible</a> since 3.0) * @deprecated Use {@link #directExecutor()} if you only require an {@link Executor} and * {@link #newDirectExecutorService()} if you need a {@link ListeningExecutorService}. This * method will be removed in August 2016. */ @Deprecated @GwtIncompatible public static ListeningExecutorService sameThreadExecutor() { return new DirectExecutorService(); } // See sameThreadExecutor javadoc for behavioral notes. @GwtIncompatible // TODO private static final class DirectExecutorService extends AbstractListeningExecutorService { /** * Lock used whenever accessing the state variables (runningTasks, shutdown) of the executor */ private final Object lock = new Object(); /* * Conceptually, these two variables describe the executor being in * one of three states: * - Active: shutdown == false * - Shutdown: runningTasks > 0 and shutdown == true * - Terminated: runningTasks == 0 and shutdown == true */ @GuardedBy("lock") private int runningTasks = 0; @GuardedBy("lock") private boolean shutdown = false; @Override public void execute(Runnable command) { startTask(); try { command.run(); } finally { endTask(); } } @Override public boolean isShutdown() { synchronized (lock) { return shutdown; } } @Override public void shutdown() { synchronized (lock) { shutdown = true; if (runningTasks == 0) { lock.notifyAll(); } } } // See sameThreadExecutor javadoc for unusual behavior of this method. @Override public List<Runnable> shutdownNow() { shutdown(); return Collections.emptyList(); } @Override public boolean isTerminated() { synchronized (lock) { return shutdown && runningTasks == 0; } } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); synchronized (lock) { while (true) { if (shutdown && runningTasks == 0) { return true; } else if (nanos <= 0) { return false; } else { long now = System.nanoTime(); TimeUnit.NANOSECONDS.timedWait(lock, nanos); nanos -= System.nanoTime() - now; // subtract the actual time we waited } } } } /** * Checks if the executor has been shut down and increments the running task count. * * @throws RejectedExecutionException if the executor has been previously shutdown */ private void startTask() { synchronized (lock) { if (shutdown) { throw new RejectedExecutionException("Executor already shutdown"); } runningTasks++; } } /** * Decrements the running task count. */ private void endTask() { synchronized (lock) { int numRunning = --runningTasks; if (numRunning == 0) { lock.notifyAll(); } } } } /** * Creates an executor service that runs each task in the thread that invokes * {@code execute/submit}, as in {@link CallerRunsPolicy} This applies both to individually * submitted tasks and to collections of tasks submitted via {@code invokeAll} or * {@code invokeAny}. In the latter case, tasks will run serially on the calling thread. Tasks are * run to completion before a {@code Future} is returned to the caller (unless the executor has * been shutdown). * * <p>Although all tasks are immediately executed in the thread that submitted the task, this * {@code ExecutorService} imposes a small locking overhead on each task submission in order to * implement shutdown and termination behavior. * * <p>The implementation deviates from the {@code ExecutorService} specification with regards to * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing * tasks. Second, the returned list will always be empty, as any submitted task is considered to * have started execution. This applies also to tasks given to {@code invokeAll} or * {@code invokeAny} which are pending serial execution, even the subset of the tasks that have * not yet started execution. It is unclear from the {@code ExecutorService} specification if * these should be included, and it's much easier to implement the interpretation that they not * be. Finally, a call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls * to {@code invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the * tasks may already have been executed. * * @since 18.0 (present as MoreExecutors.sameThreadExecutor() since 10.0) */ @GwtIncompatible // TODO public static ListeningExecutorService newDirectExecutorService() { return new DirectExecutorService(); } /** * Returns an {@link Executor} that runs each task in the thread that invokes * {@link Executor#execute execute}, as in {@link CallerRunsPolicy}. * * <p>This instance is equivalent to:{@code * final class DirectExecutor implements Executor { * public void execute(Runnable r) { * r.run(); * } * }}</pre> * * <p>This should be preferred to {@link #newDirectExecutorService()} because the implementing the * {@link ExecutorService} subinterface necessitates significant performance overhead. * * @since 18.0 */ public static Executor directExecutor() { return DirectExecutor.INSTANCE; } /** See {@link #directExecutor} for behavioral notes. */ private enum DirectExecutor implements Executor { INSTANCE; @Override public void execute(Runnable command) { command.run(); } @Override public String toString() { return "MoreExecutors.directExecutor()"; } } /** * Creates an {@link ExecutorService} whose {@code submit} and {@code * invokeAll} methods submit {@link ListenableFutureTask} instances to the given delegate * executor. Those methods, as well as {@code execute} and {@code invokeAny}, are implemented in * terms of calls to {@code * delegate.execute}. All other methods are forwarded unchanged to the delegate. This implies that * the returned {@code ListeningExecutorService} never calls the delegate's {@code submit}, * {@code invokeAll}, and {@code * invokeAny} methods, so any special handling of tasks must be implemented in the delegate's * {@code execute} method or by wrapping the returned {@code * ListeningExecutorService}. * * <p>If the delegate executor was already an instance of {@code * ListeningExecutorService}, it is returned untouched, and the rest of this documentation does * not apply. * * @since 10.0 */ @GwtIncompatible // TODO public static ListeningExecutorService listeningDecorator(ExecutorService delegate) { return (delegate instanceof ListeningExecutorService) ? (ListeningExecutorService) delegate : (delegate instanceof ScheduledExecutorService) ? new ScheduledListeningDecorator((ScheduledExecutorService) delegate) : new ListeningDecorator(delegate); } /** * Creates a {@link ScheduledExecutorService} whose {@code submit} and {@code invokeAll} methods * submit {@link ListenableFutureTask} instances to the given delegate executor. Those methods, as * well as {@code execute} and {@code invokeAny}, are implemented in terms of calls to {@code * delegate.execute}. All other methods are forwarded unchanged to the delegate. This implies that * the returned {@code ListeningScheduledExecutorService} never calls the delegate's {@code * submit}, {@code invokeAll}, and {@code invokeAny} methods, so any special handling of tasks * must be implemented in the delegate's {@code execute} method or by wrapping the returned {@code * ListeningScheduledExecutorService}. * * <p>If the delegate executor was already an instance of {@code * ListeningScheduledExecutorService}, it is returned untouched, and the rest of this * documentation does not apply. * * @since 10.0 */ @GwtIncompatible // TODO public static ListeningScheduledExecutorService listeningDecorator( ScheduledExecutorService delegate) { return (delegate instanceof ListeningScheduledExecutorService) ? (ListeningScheduledExecutorService) delegate : new ScheduledListeningDecorator(delegate); } @GwtIncompatible // TODO private static class ListeningDecorator extends AbstractListeningExecutorService { private final ExecutorService delegate; ListeningDecorator(ExecutorService delegate) { this.delegate = checkNotNull(delegate); } @Override public final boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return delegate.awaitTermination(timeout, unit); } @Override public final boolean isShutdown() { return delegate.isShutdown(); } @Override public final boolean isTerminated() { return delegate.isTerminated(); } @Override public final void shutdown() { delegate.shutdown(); } @Override public final List<Runnable> shutdownNow() { return delegate.shutdownNow(); } @Override public final void execute(Runnable command) { delegate.execute(command); } } @GwtIncompatible // TODO private static final class ScheduledListeningDecorator extends ListeningDecorator implements ListeningScheduledExecutorService { @SuppressWarnings("hiding") final ScheduledExecutorService delegate; ScheduledListeningDecorator(ScheduledExecutorService delegate) { super(delegate); this.delegate = checkNotNull(delegate); } @Override public ListenableScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { TrustedListenableFutureTask<Void> task = TrustedListenableFutureTask.create(command, null); ScheduledFuture<?> scheduled = delegate.schedule(task, delay, unit); return new ListenableScheduledTask<Void>(task, scheduled); } @Override public <V> ListenableScheduledFuture |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.