com.tinspx.util.concurrent.LimitedExecutorService.java Source code

Java tutorial

Introduction

Here is the source code for com.tinspx.util.concurrent.LimitedExecutorService.java

Source

/* 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);
            }
        }
    }
}