Java tutorial
/* Copyright (C) 2013-2014 Ian Teune <ian.teune@gmail.com> * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.tinspx.util.concurrent; import com.google.common.base.Function; import com.google.common.base.Functions; import static com.google.common.base.Preconditions.*; import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.base.Ticker; import com.google.common.collect.Collections2; import com.google.common.collect.Iterables; import com.google.common.collect.Lists; import com.google.common.collect.MapMaker; import com.google.common.collect.Maps; import com.google.common.util.concurrent.ForwardingListenableFuture; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFutureTask; import com.google.common.util.concurrent.ListenableScheduledFuture; import com.google.common.util.concurrent.ListeningScheduledExecutorService; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.RateLimiter; import com.google.common.util.concurrent.SettableFuture; import java.util.ArrayDeque; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Queue; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Delayed; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.RunnableFuture; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.ReentrantLock; import javax.annotation.Nullable; import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.NotThreadSafe; import javax.annotation.concurrent.ThreadSafe; import lombok.NonNull; import lombok.ToString; import lombok.experimental.Delegate; import lombok.extern.slf4j.Slf4j; /** * An {@link ListeningScheduledExecutorService} that limits the rate at which * tasks can be executed. * <p> * Execution limiting is controlled by {@link Limiter Limiter} instances. * {@code Limiter} is very basic interface that resembles a very simple * {@code Semaphore}. {@link Builder Builder} supplies several default * implementations based on {@link Semaphore}, {@link RateLimiter}, and * {@link DelayedSemaphore}. * <p> * Execution rate limiting can be associated with arbitrary {@code Object} keys. * Each {@code execut/submit/schedule} method provides a version that takes an * {@code Object} key as the first parameter. Tasks submitted with the same key * use the same {@code Limiter} instance to rate limit their execution. Using * these keys, different groups of tasks can have different rate limits. The * normal {@link ScheduledExecutorService} methods that don't have a {@code key} * parameter use a common default key ({@link #execute(Runnable)} uses a * shared "default" key whereas {@link #execute(Object, Runnable)} uses an * explicit key). {@code null} keys are not allowed. * <p> * The most flexible way to provide {@link Limiter}s to {@code LimitedExcutor} * is through {@link Builder#limiter(Function)}. The provided function takes an * execution {@code key} and provides a {@code Limiter} that will be used to * rate limit all tasks submitted with that key. The Function will be used to * convert a {@code key} into a {@code Limiter} typically only once per unique * {@code key}. This flexibility is often not needed, so {@code Builder} * provides many alternatives for configuring how {@code Limiter}s are created. * <p> * All {@code execut/submit/schedule} methods also provide a version that takes * a {@link ListenableFuture} as its last parameter named * {@code completionFuture}. These methods are provided for when the task is not * considered complete when the {@code Runnable} or {@code Callable} completes. * Rather, the completion of the task is determined by the completion of the * provided {@code completionFuture} parameter. When using this method, the * caller must ensure that the {@code completionFuture} always completes (either * through success or failure), or else {@code Limiter} permits may be lost. * <p> * Internally, {@code keys} are mapped to their {@code Limiter} using a * {@link ConcurrentMap}. This {@code ConcurrentMap} may optionally be provided * through a {@link MapMaker} in {@link Builder#mapMaker(MapMaker) mapMaker}. * Providing a {@code MapMaker} allows the concurrency level to be changed from * the default. * <p> <br> * The following code creates a {@code LimitedExecutorService} that uses a * {@link RateLimiter} to only allow one task per second to to be executed: * <pre> * ScheduledExecutorService delegate = ...; * LimitedExecutorService.builder().delegate(delegate).rateLimiter(1.0).build(); * </pre> * If more than one task is submitted per second, they are queued and * executed at a rate no faster than once per second. * <p> <br> * The following code creates a {@code LimitedExecutorService} that uses a * {@link Semaphore} to only allow 2 tasks to run at the same time: * <pre> * ScheduledExecutorService delegate = ...; * LimitedExecutorService.builder().delegate(delegate).semaphore(2).build(); * </pre> * If more than two tasks are submitted at time, they are queued until * there are less than 2 tasks running. This same functionality could be * achieved using an Executor with only 2 Threads. However, * {@code LimitedExecutorService} also allows rate limiting to be applied * independently to different groups of tasks by using methods that take a * {@code key} argument, such as {@link #submit(Object, Callable)}. Tasks that * are submitted with the same {@code key} share the same rate limiting * (internally they share the same {@code Limiter}). * * @see Semaphore * @see RateLimiter * @see DelayedSemaphore * @see TimedSemaphore * @author Ian */ @ThreadSafe @ToString @Slf4j public class LimitedExecutorService extends AbstractExecutorService implements ListeningScheduledExecutorService { /** * Responsible for limiting how often tasks can be run on a * {@code LimitedExecutorService}. Each {@code Runnable/Callable} will * attempt to acquire a single permit through {@link #tryAcquire()} before * being executed in the {@code LimitedExecutorService}. Once the task has * successfully acquired a permit and has completed its execution, its * permit will be released through {@link #release()}. * <p> * {@code Limiter} methods are guaranteed to be externally synchronized; it * is guaranteed that only one thread will attempt to call any of the * {@code Limiter} methods at any given time. If possible, it is recommended * for the {@code Limiter} to do no internal synchronization/locking. * Obviously, this is not possible using the several default * {@code Limiter}s that utilize already thread-safe classes (Semaphore, * RateLimiter). */ @NotThreadSafe public interface Limiter { /** * Try to acquire a permit to run a single task only if one can be * acquired without waiting. * * @return true if a permit was successfully acquired and a single task * may be executed */ boolean tryAcquire(); /** * Releases a permit previously acquired from a successful call to * {@link #tryAcquire()}. Indicates that a task has completed and its * permit can be reclaimed. */ void release(); /** * Determines the estimated time in nanoseconds until the next permit * will become available. This method should return one of the * following: * <ul> * <li>A negative number indicates that there are no permits available * and one will not become available until one is released through * {@link #release()}.</li> * <li>0 indicates a permit is ready for immediate acquisition and the * next call to {@link #tryAcquire()} will return true.</li> * <li>A positive number represents the time in nanoseconds until the * next permit becomes available.</li> * </ul> * * @return the estimated wait in nanoseconds until a permit becomes * available, 0 to indicate a permit is available, or -1 if a permit * will not become available until one is released */ long estimatedWait(); } static int checkPermits(int permits) { checkArgument(permits > 0, "permits must be positive (%s)", permits); return permits; } /** * A non thread safe Semaphore. Used when the Semaphores cannot be accessed * outside the {@code LimitedExecutorService} as Limiters don't need * internal synchronization. */ @ToString static class SemaphoreLimiter implements Limiter { final int permits; int available; public SemaphoreLimiter(int permits) { this.permits = checkPermits(permits); this.available = permits; } @Override public boolean tryAcquire() { if (available > 0) { available--; return true; } return false; } @Override public void release() { if (available == permits) { throw new IllegalStateException(String.format("all %d permits available", permits)); } available++; } @Override public long estimatedWait() { return available > 0 ? 0 : -1; } } @ToString static class SemaphoreAdaptorLimiter implements Limiter { final Semaphore delegate; public SemaphoreAdaptorLimiter(Semaphore delegate) { this.delegate = checkNotNull(delegate); } @Override public boolean tryAcquire() { return delegate.tryAcquire(); } @Override public void release() { delegate.release(); } @Override public long estimatedWait() { return delegate.availablePermits() > 0 ? 0 : -1; } } @ToString static class RateLimiterLimiter implements Limiter { final RateLimiter delegate; public RateLimiterLimiter(RateLimiter delegate) { this.delegate = checkNotNull(delegate); } @Override public boolean tryAcquire() { return delegate.tryAcquire(); } @Override public void release() { } @Override public long estimatedWait() { // 1/rate converts to seconds per permit, *10^9 ns/s to get nanos per permit return (long) (1000000000 / delegate.getRate()); } } @ToString static class DelayedSemaphoreLimiter implements Limiter { @Delegate(types = Limiter.class) final DelayedSemaphore delegate; public DelayedSemaphoreLimiter(DelayedSemaphore delegate) { this.delegate = checkNotNull(delegate); } } @ToString static class TimedSemaphoreLimiter implements Limiter { final TimedSemaphore delegate; public TimedSemaphoreLimiter(TimedSemaphore delegate) { this.delegate = checkNotNull(delegate); } @Override public boolean tryAcquire() { return delegate.tryAcquire(); } @Override public void release() { } @Override public long estimatedWait() { return delegate.estimatedWait(); } } static final Function<Semaphore, Limiter> SEMAPHORE = new Function<Semaphore, Limiter>() { @Override public Limiter apply(Semaphore input) { return new SemaphoreAdaptorLimiter(input); } }; static final Function<Integer, Limiter> SEMAPHORE_PERMITS = new Function<Integer, Limiter>() { @Override public Limiter apply(Integer input) { return new SemaphoreLimiter(input); } }; static final Function<RateLimiter, Limiter> RATELIMTER = new Function<RateLimiter, Limiter>() { @Override public Limiter apply(RateLimiter input) { return new RateLimiterLimiter(input); } }; /** * If we know that the DelayedSemaphores cannot be accessed outside this * class, the unsynchronized {@link DelayedSemaphore#asLimiter()} can be * used. However, if the DelayedSemaphore can be accessed outside the class, * the normal synchronized methods must be used ({@link #DS_EXTERNAL}) as * the user could be using it at the same time. */ static final Function<DelayedSemaphore, Limiter> DS_INTERNAL = new Function<DelayedSemaphore, Limiter>() { @Override public Limiter apply(DelayedSemaphore input) { return input.asLimiter(); } }; static final Function<DelayedSemaphore, Limiter> DS_EXTERNAL = new Function<DelayedSemaphore, Limiter>() { @Override public Limiter apply(DelayedSemaphore input) { return new DelayedSemaphoreLimiter(input); } }; static final Function<TimedSemaphore, Limiter> TS_INTERNAL = new Function<TimedSemaphore, Limiter>() { @Override public Limiter apply(TimedSemaphore input) { return input.asLimiter(); } }; static final Function<TimedSemaphore, Limiter> TS_EXTERNAL = new Function<TimedSemaphore, Limiter>() { @Override public Limiter apply(TimedSemaphore input) { return new TimedSemaphoreLimiter(input); } }; static Supplier<SemaphoreLimiter> semaphoreSupplier(final int permits) { checkPermits(permits); return new Supplier<SemaphoreLimiter>() { @Override public SemaphoreLimiter get() { return new SemaphoreLimiter(permits); } }; } public static Supplier<RateLimiter> rateLimiterSupplier(final double permitsPerSecond) { checkArgument(permitsPerSecond > 0.0 && !Double.isNaN(permitsPerSecond), "permitsPerSecond must be positive (%s)", permitsPerSecond); return new Supplier<RateLimiter>() { @Override public RateLimiter get() { return RateLimiter.create(permitsPerSecond); } }; } public static Supplier<RateLimiter> rateLimiterSupplier(final double permitsPerSecond, final long warmupPeriod, final TimeUnit unit) { checkArgument(permitsPerSecond > 0.0 && !Double.isNaN(permitsPerSecond), "permitsPerSecond must be positive (%s)", permitsPerSecond); checkArgument(warmupPeriod >= 0, "warmupPeriod must not be negative (%s)", warmupPeriod); checkNotNull(unit); return new Supplier<RateLimiter>() { @Override public RateLimiter get() { return RateLimiter.create(permitsPerSecond, warmupPeriod, unit); } }; } /** * Returns new {@link Builder} instance */ public static Builder builder() { return new Builder(); } /** * {@code Builder} class used to configure {@link LimitedExecutorService} * instances. This class is not thread safe. * <p> * The {@link ScheduledExecutorService} delegate must be set through * {@link #delegate(ScheduledExecutorService)}. Setting a {@link MapMaker} * through {@link #mapMaker(MapMaker)} is optional. If no {@code MapMaker} * is set, a default {@link ConcurrentMap} is created by calling * {@link Maps#newConcurrentMap()}. The {@link Limiter Limiter} * Function must be set through one of the supplied methods. */ @NotThreadSafe public static class Builder { ScheduledExecutorService delegate; Function<Object, ? extends Limiter> limiterFunction; MapMaker mapMaker; boolean warnOnEmptyLimiter = false; boolean throwOnEmptyLimiter = true; Object defaultKey; Builder() { } public LimitedExecutorService build() { return new LimitedExecutorService(delegate, limiterFunction, mapMaker != null ? mapMaker.<Object, KeyRunner>makeMap() : Maps.<Object, KeyRunner>newConcurrentMap(), warnOnEmptyLimiter, throwOnEmptyLimiter, defaultKey, null); } /** * Sets the delegate {@code ScheduledExecutorService} that will execute * all tasks submitted to the {@code LimitedExecutorService}. */ public Builder delegate(ScheduledExecutorService delegate) { this.delegate = delegate; return this; } /** * Sets the the default key. All {@code ScheduledExecutorService} * methods that do not take a {@code key} will use {@code defaultKey} as * the key. If the default key is not set using this method, an * arbitrary, non-null {@code Object} will be used as the default key. */ public Builder defaultKey(Object defaultKey) { this.defaultKey = defaultKey; return this; } /** * Sets the {@code MapMaker} used to acquire a {@link ConcurrentMap} * that will map execution {@code keys} to its associated * {@link Limiter Limiter}. This is an optional setting (a default Map * will be used if not set). Setting this {@code MapMaker} allows an * appropriate {@link MapMaker#concurrencyLevel(int) concurrency level} * to be set. However, the more useful setting is * {@link MapMaker#weakValues()}. If weak values are enabled, execution * keys that are not in use can be garbage collected. This may be * necessary when a large number of short lived execution keys are used. * Without enabling weak values, these execution keys will never be * removed from the map. Typically, * {@link MapMaker#weakKeys() weak keys} should <i>not</i> be enabled. */ public Builder mapMaker(MapMaker mapMaker) { this.mapMaker = mapMaker; return this; } /** * If set to true, a warning message will be logged if a newly acquired * {@link Limiter Limiter} is initially empty. This may indicate an * error as an empty {@code Limiter Limiter} will never allow tasks to * be run. If {@link #throwOnEmptyLimiter(boolean)} is set to true, an * exception will be thrown instead of logging the warning. * <p> * Defaults to {@code false}. ({@link #throwOnEmptyLimiter(boolean)} * defaults to {@code true}) */ public Builder warnOnEmptyLimiter(boolean warnOnEmptyLimiter) { this.warnOnEmptyLimiter = warnOnEmptyLimiter; return this; } /** * If set to true, an {@link IllegalStateException} will be thrown if a * newly acquired {@link Limiter Limiter} is initially empty. This may * indicate an error as an empty {@code Limiter Limiter} will never * allow tasks to be run. * <p> * Defaults to {@code true}. */ public Builder throwOnEmptyLimiter(boolean throwOnEmptyLimiter) { this.throwOnEmptyLimiter = throwOnEmptyLimiter; return this; } /** * Configures how {@link Limiter Limiter}s are acquired. The supplied * Function will be provided the execution {@code key} as its input and * should return a {@code Limiter} that will be used rate limit all * tasks that are submitted with the supplied key (the default key will * be an arbitrary, non-null {@code Object} unless explicitly set * through {@link #defaultKey(Object)}). Typically, each unique * {@code key} will be converted to a {@code Limiter} through this * Function only once. */ public Builder limiter(Function<Object, ? extends Limiter> limiterFunction) { this.limiterFunction = limiterFunction; return this; } public Builder limiter(Supplier<? extends Limiter> limiterSupplier) { this.limiterFunction = Functions.forSupplier(limiterSupplier); return this; } public Builder semaphore(int permits) { return limiter(semaphoreSupplier(permits)); } public Builder semaphore(Supplier<Semaphore> semaphoreSupplier) { return limiter(Suppliers.compose(SEMAPHORE, semaphoreSupplier)); } /** * Converts Object keys into the number of permits for a Semaphore. * <p> * Similar to {@link #semaphore(Function)} except the Function produces * the number of permits for the {@link Semaphore} instead of directly * creating the {@code Semaphore}. */ public Builder semaphorePermits(Function<Object, Integer> permitFunction) { return limiter(Functions.compose(SEMAPHORE_PERMITS, permitFunction)); } /** * Converts Object keys into a {@link Semaphore}. * <p> * Similar to {@link #limiter(Function)} except the Function produces a * {@code Semaphore} instead of directly creating the * {@link Limiter Limiter}. */ public Builder semaphore(Function<Object, Semaphore> semaphoreFunction) { return limiter(Functions.compose(SEMAPHORE, semaphoreFunction)); } public Builder rateLimiter(double permitsPerSecond) { return rateLimiter(rateLimiterSupplier(permitsPerSecond)); } public Builder rateLimiter(double permitsPerSecond, long warmupPeriod, TimeUnit unit) { return rateLimiter(rateLimiterSupplier(permitsPerSecond, warmupPeriod, unit)); } public Builder rateLimiter(Supplier<RateLimiter> rateLimiterSupplier) { return limiter(Suppliers.compose(RATELIMTER, rateLimiterSupplier)); } /** * Converts Object keys into a {@link RateLimiter}. * <p> * Similar to {@link #limiter(Function)} except the Function produces a * {@code RateLimiter} instead of directly creating the * {@link Limiter Limiter}. */ public Builder rateLimiter(Function<Object, RateLimiter> rateLimiterFunction) { return limiter(Functions.compose(RATELIMTER, rateLimiterFunction)); } public Builder delayedSemaphore(int permits, long delay) { return delayedSemaphore(true, DelayedSemaphore.supplier(permits, delay)); } public Builder delayedSemaphore(int permits, long delay, Ticker ticker) { return delayedSemaphore(true, DelayedSemaphore.supplier(permits, delay, ticker)); } public Builder delayedSemaphore(Supplier<DelayedSemaphore> delayedSemaphoreSupplier) { return delayedSemaphore(false, delayedSemaphoreSupplier); } private Builder delayedSemaphore(boolean internal, Supplier<DelayedSemaphore> delayedSemaphoreSupplier) { return limiter(Suppliers.compose(internal ? DS_INTERNAL : DS_EXTERNAL, delayedSemaphoreSupplier)); } /** * Converts Object keys into a {@link DelayedSemaphore}. * <p> * Similar to {@link #limiter(Function)} except the Function produces a * {@code DelayedSemaphore} instead of directly creating the * {@link Limiter Limiter}. */ public Builder delayedSemaphore(Function<Object, DelayedSemaphore> delayedSemaphoreFunction) { return limiter(Functions.compose(DS_EXTERNAL, delayedSemaphoreFunction)); } public Builder timedSemaphore(int limit, long period, TimeUnit unit) { return timedSemaphore(true, TimedSemaphore.supplier(limit, period, unit)); } public Builder timedSemaphore(int limit, long period, TimeUnit unit, Ticker ticker) { return timedSemaphore(true, TimedSemaphore.supplier(limit, period, unit, ticker)); } public Builder timedSemaphore(Supplier<TimedSemaphore> timedSemaphoreSupplier) { return timedSemaphore(false, timedSemaphoreSupplier); } private Builder timedSemaphore(boolean internal, Supplier<TimedSemaphore> timedSemaphoreSupplier) { return limiter(Suppliers.compose(internal ? TS_INTERNAL : TS_EXTERNAL, timedSemaphoreSupplier)); } /** * Converts Object keys into a {@link TimedSemaphore}. * <p> * Similar to {@link #limiter(Function)} except the Function produces a * {@link TimedSemaphore} instead of directly creating the * {@link Limiter Limiter}. */ public Builder timedSemaphore(Function<Object, TimedSemaphore> timedSemaphoreFunction) { return limiter(Functions.compose(TS_EXTERNAL, timedSemaphoreFunction)); } } final ScheduledExecutorService delegate; final Function<Object, ? extends Limiter> limiterFunction; final ConcurrentMap<Object, KeyRunner> keyLimiterMap; final Object defaultKey; final KeyRunner defaultKeyRunner; final boolean warnOnEmptyLimiter; final boolean throwOnEmptyLimiter; LimitedExecutorService(ScheduledExecutorService delegate, Function<Object, ? extends Limiter> limiterFunction, ConcurrentMap<Object, KeyRunner> keyLimiterMap, boolean warnEmptyLimiters, boolean throwOnEmptyLimiter, @Nullable Object defaultKey, @Nullable KeyRunner defaultKeyRunner) { this.delegate = checkNotNull(delegate); this.limiterFunction = checkNotNull(limiterFunction); this.keyLimiterMap = checkNotNull(keyLimiterMap); this.defaultKey = defaultKey != null ? defaultKey : new Object(); if (defaultKeyRunner != null) { checkState(defaultKeyRunner.key == this.defaultKey); this.defaultKeyRunner = defaultKeyRunner; } else { this.defaultKeyRunner = new KeyRunner(this.defaultKey, limiterFunction.apply(this.defaultKey)); } this.warnOnEmptyLimiter = warnEmptyLimiters; this.throwOnEmptyLimiter = throwOnEmptyLimiter; } /** * Returns the the delegate {@code ScheduledExecutorService} used to execute * and schedule all tasks. */ public ScheduledExecutorService delegate() { return delegate; } @Override public List<Runnable> shutdownNow() { return delegate.shutdownNow(); } @Override public void shutdown() { delegate.shutdown(); } @Override public boolean isTerminated() { return delegate.isTerminated(); } @Override public boolean isShutdown() { return delegate.isShutdown(); } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return delegate.awaitTermination(timeout, unit); } /** * Returns a new {@code LimitedExecutorService} that is identical to this * instance except with specified default {@code key}. * * @see #withKey(Object) */ public LimitedExecutorService withDefaultKey(@NonNull Object key) { return new LimitedExecutorService(delegate, limiterFunction, keyLimiterMap, warnOnEmptyLimiter, throwOnEmptyLimiter, key, forKey(key)); } /** * Returns a {@code ListeningScheduledExecutorService} that forwards all * submitted tasks to this {@code LimitedExecutorService} using the * specified {@code key}. * * @see #withDefaultKey(Object) */ public ListeningScheduledExecutorService withKey(@NonNull final Object key) { return new ListeningScheduledExecutorService() { @Override public ListenableScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { return LimitedExecutorService.this.schedule(key, command, delay, unit); } @Override public <V> ListenableScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) { return LimitedExecutorService.this.schedule(key, callable, delay, unit); } @Override public ListenableScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { return LimitedExecutorService.this.scheduleAtFixedRate(key, command, initialDelay, period, unit); } @Override public ListenableScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { return LimitedExecutorService.this.scheduleWithFixedDelay(key, command, initialDelay, delay, unit); } @Override public void shutdown() { LimitedExecutorService.this.shutdown(); } @Override public List<Runnable> shutdownNow() { return LimitedExecutorService.this.shutdownNow(); } @Override public boolean isShutdown() { return LimitedExecutorService.this.isShutdown(); } @Override public boolean isTerminated() { return LimitedExecutorService.this.isTerminated(); } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return LimitedExecutorService.this.awaitTermination(timeout, unit); } @Override public <T> ListenableFuture<T> submit(Callable<T> task) { return LimitedExecutorService.this.submit(key, task); } @Override public <T> ListenableFuture<T> submit(Runnable task, @Nullable T result) { return LimitedExecutorService.this.submit(key, task, result); } @Override public ListenableFuture<?> submit(Runnable task) { return LimitedExecutorService.this.submit(key, task); } @Override public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { return LimitedExecutorService.this.invokeAll(key, tasks); } @Override public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { return LimitedExecutorService.this.invokeAll(key, tasks, timeout, unit); } @Override public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { return LimitedExecutorService.this.invokeAny(key, tasks); } @Override public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return LimitedExecutorService.this.invokeAny(key, tasks, timeout, unit); } @Override public void execute(Runnable command) { LimitedExecutorService.this.execute(key, command); } @Override public String toString() { return String.format("%s with key [%s]", LimitedExecutorService.this, key); } }; } public List<ListenableFuture<Void>> executeAll(Iterable<? extends Runnable> commands) { return executeAll(defaultKey, commands); } public List<ListenableFuture<Void>> executeAll(Object key, Iterable<? extends Runnable> commands) { return forKey(key).submitAll(Iterables.transform(commands, ThreadUtils.<Void>callableFunction())); } public <T> List<ListenableFuture<T>> submitAll(Iterable<? extends Callable<T>> tasks) { return submitAll(defaultKey, tasks); } public <T> List<ListenableFuture<T>> submitAll(Object key, Iterable<? extends Callable<T>> tasks) { return forKey(key).submitAll(tasks); } @Override public void execute(Runnable command) { execute(defaultKey, command); } public ListenableFuture<?> execute(Runnable command, ListenableFuture<?> completionFuture) { return execute(defaultKey, command, completionFuture); } public ListenableFuture<?> execute(Object key, Runnable command) { return forKey(key).submit(Executors.callable(command)); } public ListenableFuture<?> execute(Object key, Runnable command, ListenableFuture<?> completionFuture) { return forKey(key).submit(Executors.callable(command), completionFuture); } @Override public <T> ListenableFuture<T> submit(Runnable task, @Nullable T result) { return submit(defaultKey, task, result); } public <T> ListenableFuture<T> submit(Runnable task, @Nullable T result, ListenableFuture<?> completionFuture) { return submit(defaultKey, task, result, completionFuture); } public <T> ListenableFuture<T> submit(Object key, Runnable task, @Nullable T result) { return forKey(key).submit(Executors.callable(task, result)); } public <T> ListenableFuture<T> submit(Object key, Runnable task, @Nullable T result, ListenableFuture<?> completionFuture) { return forKey(key).submit(Executors.callable(task, result), completionFuture); } @Override public ListenableFuture<?> submit(Runnable task) { return submit(defaultKey, task); } public ListenableFuture<?> submit(Runnable task, ListenableFuture<?> completionFuture) { return submit(defaultKey, task, completionFuture); } public ListenableFuture<?> submit(Object key, Runnable task) { return forKey(key).submit(Executors.callable(task)); } public ListenableFuture<?> submit(Object key, Runnable task, ListenableFuture<?> completionFuture) { return forKey(key).submit(Executors.callable(task), completionFuture); } @Override public <T> ListenableFuture<T> submit(Callable<T> task) { if (task instanceof KeyCallable) { return submit(((KeyCallable) task).key, task); } else { return submit(defaultKey, task); } } public <T> ListenableFuture<T> submit(Callable<T> task, ListenableFuture<?> completionFuture) { return submit(defaultKey, task, completionFuture); } public <T> ListenableFuture<T> submit(Object key, Callable<T> task) { return forKey(key).submit(task); } public <T> ListenableFuture<T> submit(Object key, Callable<T> task, ListenableFuture<?> completionFuture) { return forKey(key).submit(task, completionFuture); } @Override public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return invokeAny(defaultKey, tasks, timeout, unit); } public <T> T invokeAny(Object key, Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return super.invokeAny(transform(key, tasks), timeout, unit); } @Override public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { return invokeAny(defaultKey, tasks); } public <T> T invokeAny(Object key, Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { return super.invokeAny(transform(key, tasks)); } @Override public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { return invokeAll(defaultKey, tasks, timeout, unit); } public <T> List<Future<T>> invokeAll(Object key, Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { return super.invokeAll(transform(key, tasks), timeout, unit); } @Override public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { return invokeAll(defaultKey, tasks); } public <T> List<Future<T>> invokeAll(Object key, Collection<? extends Callable<T>> tasks) throws InterruptedException { return super.invokeAll(transform(key, tasks)); } static <T> Collection<KeyCallable<T>> transform(final Object key, Collection<? extends Callable<T>> tasks) { checkNotNull(key); return Collections2.transform(tasks, new Function<Callable<T>, KeyCallable<T>>() { @Override public KeyCallable<T> apply(Callable<T> input) { return new KeyCallable<T>(key, input); } }); } /** * Wraps a Callable passed to invokeAll and invokeAny and captures the key * associated with task. The saved key is used by * {@link #newTaskFor(Callable)}, which {@link AbstractExecutorService} uses * when implementing invokeAll and invokeAny. */ @ToString static class KeyCallable<T> implements Callable<T> { final Object key; final Callable<T> delegate; public KeyCallable(Object key, Callable<T> delegate) { this.key = checkNotNull(key); this.delegate = checkNotNull(delegate); } @Override public T call() throws Exception { return delegate.call(); } } @Override protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return forKey(((KeyCallable) callable).key).newRunnableTask(callable); } @Override protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { //should never be called, AbstractExecutorService uses this for //submitting Runnables, but all execute/submit methods are overridden throw new UnsupportedOperationException(); } @Override public ListenableScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { return schedule(defaultKey, command, delay, unit); } public ListenableScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit, ListenableFuture<?> completionFuture) { return schedule(defaultKey, command, delay, unit, completionFuture); } public ListenableScheduledFuture<?> schedule(Object key, Runnable command, long delay, TimeUnit unit) { return forKey(key).schedule(Executors.callable(command), delay, unit); } public ListenableScheduledFuture<?> schedule(Object key, Runnable command, long delay, TimeUnit unit, ListenableFuture<?> completionFuture) { return forKey(key).schedule(Executors.callable(command), delay, unit, completionFuture); } @Override public <V> ListenableScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) { return schedule(defaultKey, callable, delay, unit); } public <V> ListenableScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit, ListenableFuture<?> completionFuture) { return schedule(defaultKey, callable, delay, unit, completionFuture); } public <V> ListenableScheduledFuture<V> schedule(Object key, Callable<V> callable, long delay, TimeUnit unit) { return forKey(key).schedule(callable, delay, unit); } public <V> ListenableScheduledFuture<V> schedule(Object key, Callable<V> callable, long delay, TimeUnit unit, ListenableFuture<?> completionFuture) { return forKey(key).schedule(callable, delay, unit, completionFuture); } @Override public ListenableScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { return scheduleAtFixedRate(defaultKey, command, initialDelay, period, unit); } public ListenableScheduledFuture<?> scheduleAtFixedRate(Object key, Runnable command, long initialDelay, long period, TimeUnit unit) { return forKey(key).scheduleAtFixedRate(command, initialDelay, period, unit); } @Override public ListenableScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { return scheduleWithFixedDelay(defaultKey, command, initialDelay, delay, unit); } public ListenableScheduledFuture<?> scheduleWithFixedDelay(Object key, Runnable command, long initialDelay, long delay, TimeUnit unit) { return forKey(key).scheduleWithFixedDelay(command, initialDelay, delay, unit); } /** * retrieves the KeyRunner for the given key, creating it if necessary */ KeyRunner forKey(final @NonNull Object key) { if (defaultKey.equals(key)) { return defaultKeyRunner; } KeyRunner kr = keyLimiterMap.get(key); if (kr == null) { kr = new KeyRunner(key, limiterFunction.apply(key)); if (keyLimiterMap.putIfAbsent(key, kr) != null) { kr = keyLimiterMap.get(key); assert kr != null; } } return kr; } /** * Used by {@link KeyRunner} to run {@code Callable} delegates */ interface TaskRunner<T> { /** * Returns a {@code ListenableFuture} that represents the state of the * {@code Callable} delegate */ ListenableFuture<T> future(); /** * Returns {@code Runnable} that, when run, will call the * {@code Callable} and update the {@code ListenableFuture} returned * from {@link #future()}. This method is only called once a permit has * been acquired. This {@code TaskRunner} must ensure that the permit is * released after the {@code Callable} completes by calling * {@link KeyRunner#taskComplete()} exactly once. */ Runnable runnable(); } static final class ToFuture<T> implements Function<TaskRunner<T>, ListenableFuture<T>> { static final ToFuture<Object> INSTANCE = new ToFuture<Object>(); @SuppressWarnings("unchecked") static <T> ToFuture<T> instance() { return (ToFuture<T>) INSTANCE; } @Override public ListenableFuture<T> apply(TaskRunner<T> input) { return input.future(); } } /** * Responsible for executing/limiting/queuing tasks for a specific key */ class KeyRunner implements Runnable { /** * although {@code key} is never accessed, keeping a reference to it * here prevents this KeyRunner from being removed from the map if * weak keys is enabled. */ final Object key; @GuardedBy("lock") final Limiter limiter; /** * Lock that guards {@link queue}, {@link #scheduled}, and * {@link #limiter}. {@code limiter} will typically be thread safe in * its own right and in most cases does not need to be guarded. However, * since {@code limiter} is only accessed when {@code queue} is * accessed, it gets guarded by {@code lock} anyways. This allows * {@link Limiter} implementations to have no internal synchronization. */ final ReentrantLock lock = new ReentrantLock(); /** * queue of pending tasks waiting for permits to become available */ @GuardedBy("lock") final Queue<TaskRunner<?>> queue = new ArrayDeque<TaskRunner<?>>(); /** * true if a future call to {@link #processQueue(boolean)} has been * scheduled for a time when a permit is expected to be available. */ @GuardedBy("lock") boolean scheduled; public KeyRunner(Object key, Limiter limiter) { this.key = checkNotNull(key); this.limiter = checkNotNull(limiter); if (warnOnEmptyLimiter || throwOnEmptyLimiter) { long est = limiter.estimatedWait(); if (est < 0) { String msg = String.format("Limiter has no permits; limiter: [%s], key: [%s], estWait: %d", limiter, key, est); if (throwOnEmptyLimiter) { throw new IllegalStateException(msg); } else { log.warn(msg); } } } } public ListenableScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { final ScheduleAtFixedRate tr = new ScheduleAtFixedRate(command); ScheduledFuture<?> sf = delegate.scheduleAtFixedRate(new RunnableTask<Object>(tr), initialDelay, period, unit); return FutureUtils.delegateListenableScheduledFuture(tr.future(), sf); } public ListenableScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { final ScheduleWithFixedDelay tr = new ScheduleWithFixedDelay(command, unit.toNanos(initialDelay), unit.toNanos(delay)); FutureUtils.linkFailure(tr, delegate.schedule(tr.taskSubmit, initialDelay, unit), false); return tr; } public <T> ListenableScheduledFuture<T> schedule(Callable<T> task, long delay, TimeUnit unit) { return schedule(new DefaultTaskRunner<T>(task), delay, unit); } public <T> ListenableScheduledFuture<T> schedule(Callable<T> task, long delay, TimeUnit unit, ListenableFuture<?> completionFuture) { return schedule(completionFutureTaskRunner(task, completionFuture), delay, unit); } public <T> ListenableScheduledFuture<T> schedule(final TaskRunner<T> tr, long delay, TimeUnit unit) { ScheduledFuture<?> sf = delegate.schedule(new RunnableTask<T>(tr), delay, unit); return FutureUtils.delegateListenableScheduledFuture(tr.future(), sf); } public <T> RunnableTask<T> newRunnableTask(Callable<T> delegate) { return new RunnableTask<T>(new DefaultTaskRunner<T>(delegate)); } /** * Used by schedule(...) methods to run a TaskRunner sometime in the * future. Can also be used to get a {@link TaskRunner} as a * RunnableFuture. Typically, this class should only be run once. * However, the scheduleWithFixedDelay and scheduleAtFixedRate use this * to run a repeating task as they use a {@link ScheduleAtFixedRate} * which can be run many times. */ @ToString class RunnableTask<T> extends ForwardingListenableFuture<T> implements Runnable, RunnableFuture<T> { final TaskRunner<T> tr; public RunnableTask(TaskRunner<T> tr) { this.tr = checkNotNull(tr); } @Override public void run() { submitScheduled(tr); } @Override protected ListenableFuture<T> delegate() { return tr.future(); } } public <T> ListenableFuture<T> submit(Callable<T> task) { return submit(new DefaultTaskRunner<T>(task)); } public <T> ListenableFuture<T> submit(Callable<T> task, ListenableFuture<?> completionFuture) { return submit(completionFutureTaskRunner(task, completionFuture)); } public <T> List<ListenableFuture<T>> submitAll(Iterable<? extends Callable<T>> tasks) { checkNotNull(tasks); List<TaskRunner<T>> runners; if (tasks instanceof Collection) { runners = Lists.newArrayListWithCapacity(((Collection) tasks).size()); } else { runners = Lists.newArrayList(); } for (Callable<T> task : tasks) { runners.add(new DefaultTaskRunner<T>(task)); } if (runners.isEmpty()) { return Collections.emptyList(); } if (runners.size() > 1) { lock.lock(); try { for (TaskRunner<?> task : runners) { queue.offer(task); } if (!scheduled) { processQueue(); } } finally { lock.unlock(); } } else { submit(runners.get(0)); } return Lists.transform(runners, ToFuture.<T>instance()); } /** * submits a task that was scheduled and therefore may be done or * canceled */ public <T> ListenableFuture<T> submitScheduled(final TaskRunner<T> tr) { return tr.future().isDone() ? tr.future() : submit(tr); } public <T> ListenableFuture<T> submit(final TaskRunner<T> tr) { checkNotNull(tr); lock.lock(); try { if (scheduled) { queue.offer(tr); } else if (queue.isEmpty()) { if (limiter.tryAcquire()) { delegate.execute(tr.runnable()); } else { queue.offer(tr); if (scheduleProcess()) { processQueue(); } } } else { queue.offer(tr); processQueue(); } } finally { lock.unlock(); } return tr.future(); } /** * Schedules {@link #processQueue(boolean)} to be called some time in * the future. * <p> * Returns true if {@link Limiter#tryAcquire() limiter.tryAcquire()} may * return true and queue processing should continue. * <p> * Returns false if processing should not continue. This will occur if a * queue process has been scheduled or if * {@link Limiter#tryAcquire() limiter.tryAcquire()} will not return * true until a task is complete and a permit has been released. * * @return true if queue processing should continue */ @GuardedBy("lock") private boolean scheduleProcess() { assert lock.isHeldByCurrentThread(); if (scheduled) { return false; } final long est = limiter.estimatedWait(); if (est < 0) { return false; } else if (est > 0) { delegate.schedule(this, est, TimeUnit.NANOSECONDS); scheduled = true; return false; } else { return true; } } @Override public void run() { lock.lock(); try { scheduled = false; processQueue(); } finally { lock.unlock(); } } @GuardedBy("lock") public void processQueue() { assert lock.isHeldByCurrentThread(); assert !scheduled; do { for (;;) { for (;;) { if (queue.isEmpty()) { return; } if (queue.peek().future().isDone()) { queue.poll(); } else { break; } } if (limiter.tryAcquire()) { delegate.execute(queue.poll().runnable()); } else { break; } } } while (scheduleProcess()); } /** * called from TaskRunner when a task completes. releases a permit * and processes the queue. */ public void taskComplete() { lock.lock(); try { limiter.release(); if (!scheduled) { processQueue(); } } finally { lock.unlock(); } } /** * Runs a Callable delegate when {@link #run() run} and calls * {@link KeyRunner#taskComplete()} when complete. */ @ToString class DefaultTaskRunner<T> implements TaskRunner<T>, Runnable { final ListenableFutureTask<T> task; public DefaultTaskRunner(Callable<T> delegate) { this.task = ListenableFutureTask.create(delegate); } @Override public void run() { try { task.run(); } finally { taskComplete(); } } @Override public ListenableFuture<T> future() { return task; } @Override public Runnable runnable() { return this; } } private <T> CompletionFutureTaskRunner<T> completionFutureTaskRunner(Callable<T> delegate, ListenableFuture<?> completionFuture) { CompletionFutureTaskRunner<T> c = new CompletionFutureTaskRunner<T>(delegate); c.addListener(completionFuture); return c; } /** * TaskRunner whose completion is determined by an external Future */ class CompletionFutureTaskRunner<T> implements TaskRunner<T>, Runnable { final ListenableFutureTask<T> task; /** * true if a permit has been acquired and must be released through * {@link #taskComplete()} */ @GuardedBy("this") boolean acquired; /** * true when the external Future has completed */ @GuardedBy("this") boolean complete; /** * true when {@link #task} is running */ @GuardedBy("this") boolean running; @GuardedBy("this") boolean taskRun; @SuppressWarnings("LeakingThisInConstructor") public CompletionFutureTaskRunner(Callable<T> delegate) { this.task = ListenableFutureTask.create(delegate); } private void addListener(ListenableFuture<?> completionFuture) { completionFuture.addListener(new Runnable() { @Override public void run() { onExternalComplete(); } }, MoreExecutors.directExecutor()); } @GuardedBy("this") private void releaseIfAcquired() { assert Thread.holdsLock(this); if (acquired) { acquired = false; taskComplete(); } } @Override public void run() { synchronized (this) { assert !running; assert !taskRun; if (complete) { releaseIfAcquired(); return; } running = true; } try { task.run(); } finally { synchronized (this) { running = false; taskRun = true; if (complete) { releaseIfAcquired(); } } } } @Override public synchronized Runnable runnable() { assert !acquired; assert !running; assert !taskRun; acquired = true; return this; } private synchronized void onExternalComplete() { assert !complete; complete = true; if (!running) { if (!taskRun) { task.cancel(false); } releaseIfAcquired(); } } @Override public ListenableFuture<T> future() { return task; } } /** * Used with scheduleAtFixedRate. */ @ToString class ScheduleAtFixedRate implements TaskRunner<Object>, Runnable { final Runnable delegate; final SettableFuture<Object> future; /** * number of task executions that are waiting to be run */ @GuardedBy("this") int waiting; /** * true if {@link #run()} is running this task */ @GuardedBy("this") boolean running; public ScheduleAtFixedRate(Runnable delegate) { this.delegate = checkNotNull(delegate); this.future = SettableFuture.create(); } /** * scheduleAtFixedRate ensures that tasks do not run concurrently. * If run is called while a task is already running, it is queued * and run immediately after the already running task completes. */ @Override public void run() { synchronized (this) { if (running) { waiting++; return; } running = true; } for (int count = 1;;) { for (; count > 0; count--) { doRun(); } synchronized (this) { if (waiting > 0) { count = waiting; waiting = 0; } else { running = false; return; } } } } /** * note that this method must always be called by {@link #run()} * regardless of whether the future is done as the acquired * permit must be released through {@link #taskComplete()} */ @SuppressWarnings({ "BroadCatchBlock", "TooBroadCatch" }) public void doRun() { try { if (!future.isDone()) { delegate.run(); } } catch (Throwable t) { future.setException(t); } finally { taskComplete(); } } @Override public ListenableFuture<Object> future() { return future; } @Override public Runnable runnable() { return this; } } /** * Used for scheduleWithFixedDelay. Instead of using the delegate * scheduleWithFixedDelay(...) method, this class reschedules itself * after every execution. */ @ToString class ScheduleWithFixedDelay extends ForwardingListenableFuture<Object> implements TaskRunner<Object>, Runnable, ListenableScheduledFuture<Object> { /** * This is the Runnable that is scheduled on * {@link LimitedExecutor#this#delegate} */ final Runnable taskSubmit = new RunnableTask<Object>(this); final SettableFuture<Object> future = SettableFuture.create(); final Runnable delegate; /** * the delay in nanoseconds between the completion of the task and * when it is executed again */ final long delayNanos; /** * the scheduled time of the next execution */ volatile long time; public ScheduleWithFixedDelay(Runnable delegate, long initDelayNanos, long delayNanos) { this.delegate = checkNotNull(delegate); checkArgument(delayNanos > 0); this.delayNanos = delayNanos; time = System.nanoTime() + initDelayNanos; } @Override @SuppressWarnings({ "BroadCatchBlock", "TooBroadCatch" }) public void run() { try { if (!future.isDone()) { delegate.run(); time = System.nanoTime() + delayNanos; LimitedExecutorService.this.delegate.schedule(taskSubmit, delayNanos, TimeUnit.NANOSECONDS); } } catch (Throwable t) { future.setException(t); } finally { taskComplete(); } } @Override public ListenableFuture<Object> future() { return future; } @Override public Runnable runnable() { return this; } @Override protected ListenableFuture<Object> delegate() { return future; } @Override public long getDelay(TimeUnit unit) { return TimeUnit.NANOSECONDS.convert(time - System.nanoTime(), unit); } @Override public int compareTo(Delayed other) { if (other == this) { return 0; } final long diff; if (other instanceof ScheduleWithFixedDelay) { diff = time - ((ScheduleWithFixedDelay) other).time; } else { diff = time - System.nanoTime() - other.getDelay(TimeUnit.NANOSECONDS); } return diff < 0 ? -1 : (diff > 0 ? 1 : 0); } } } }