001/*
002 * Copyright (C) 2012 The Guava Authors
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package com.google.common.util.concurrent.testing;
018
019import static java.util.concurrent.TimeUnit.NANOSECONDS;
020
021import com.google.common.annotations.GwtIncompatible;
022import com.google.common.collect.ImmutableList;
023import com.google.common.primitives.Longs;
024import com.google.common.util.concurrent.AbstractFuture;
025import com.google.common.util.concurrent.AbstractListeningExecutorService;
026import com.google.common.util.concurrent.ListenableScheduledFuture;
027import com.google.common.util.concurrent.ListeningScheduledExecutorService;
028import com.google.common.util.concurrent.MoreExecutors;
029import java.util.List;
030import java.util.concurrent.Callable;
031import java.util.concurrent.Delayed;
032import java.util.concurrent.ExecutorService;
033import java.util.concurrent.ScheduledExecutorService;
034import java.util.concurrent.ScheduledFuture;
035import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
036import java.util.concurrent.TimeUnit;
037
038/**
039 * Factory methods for {@link ExecutorService} for testing.
040 *
041 * @author Chris Nokleberg
042 * @since 14.0
043 */
044@GwtIncompatible
045public final class TestingExecutors {
046  private TestingExecutors() {}
047
048  /**
049   * Returns a {@link ScheduledExecutorService} that never executes anything.
050   *
051   * <p>The {@code shutdownNow} method of the returned executor always returns an empty list despite
052   * the fact that everything is still technically awaiting execution. The {@code getDelay} method
053   * of any {@link ScheduledFuture} returned by the executor will always return the max long value
054   * instead of the time until the user-specified delay.
055   */
056  public static ListeningScheduledExecutorService noOpScheduledExecutor() {
057    return new NoOpScheduledExecutorService();
058  }
059
060  /**
061   * Creates a scheduled executor service that runs each task in the thread that invokes {@code
062   * execute/submit/schedule}, as in {@link CallerRunsPolicy}. This applies both to individually
063   * submitted tasks and to collections of tasks submitted via {@code invokeAll}, {@code invokeAny},
064   * {@code schedule}, {@code scheduleAtFixedRate}, and {@code scheduleWithFixedDelay}. In the case
065   * of tasks submitted by {@code invokeAll} or {@code invokeAny}, tasks will run serially on the
066   * calling thread. Tasks are run to completion before a {@code Future} is returned to the caller
067   * (unless the executor has been shutdown).
068   *
069   * <p>The returned executor is backed by the executor returned by {@link
070   * MoreExecutors#newDirectExecutorService} and subject to the same constraints.
071   *
072   * <p>Although all tasks are immediately executed in the thread that submitted the task, this
073   * {@code ExecutorService} imposes a small locking overhead on each task submission in order to
074   * implement shutdown and termination behavior.
075   *
076   * <p>Because of the nature of single-thread execution, the methods {@code scheduleAtFixedRate}
077   * and {@code scheduleWithFixedDelay} are not supported by this class and will throw an
078   * UnsupportedOperationException.
079   *
080   * <p>The implementation deviates from the {@code ExecutorService} specification with regards to
081   * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is
082   * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing
083   * tasks. Second, the returned list will always be empty, as any submitted task is considered to
084   * have started execution. This applies also to tasks given to {@code invokeAll} or {@code
085   * invokeAny} which are pending serial execution, even the subset of the tasks that have not yet
086   * started execution. It is unclear from the {@code ExecutorService} specification if these should
087   * be included, and it's much easier to implement the interpretation that they not be. Finally, a
088   * call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls to {@code
089   * invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the tasks may
090   * already have been executed.
091   *
092   * @since 32.0.0 (taking the place of a method with a different return type from 15.0)
093   */
094  public static ListeningScheduledExecutorService sameThreadScheduledExecutor() {
095    return new SameThreadScheduledExecutorService();
096  }
097
098  private static final class NoOpScheduledExecutorService extends AbstractListeningExecutorService
099      implements ListeningScheduledExecutorService {
100
101    private volatile boolean shutdown;
102
103    @Override
104    public void shutdown() {
105      shutdown = true;
106    }
107
108    @Override
109    public List<Runnable> shutdownNow() {
110      shutdown();
111      return ImmutableList.of();
112    }
113
114    @Override
115    public boolean isShutdown() {
116      return shutdown;
117    }
118
119    @Override
120    public boolean isTerminated() {
121      return shutdown;
122    }
123
124    @Override
125    public boolean awaitTermination(long timeout, TimeUnit unit) {
126      return true;
127    }
128
129    @Override
130    public void execute(Runnable runnable) {}
131
132    @Override
133    public <V> ListenableScheduledFuture<V> schedule(
134        Callable<V> callable, long delay, TimeUnit unit) {
135      return NeverScheduledFuture.create();
136    }
137
138    @Override
139    public ListenableScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
140      return NeverScheduledFuture.create();
141    }
142
143    @Override
144    public ListenableScheduledFuture<?> scheduleAtFixedRate(
145        Runnable command, long initialDelay, long period, TimeUnit unit) {
146      return NeverScheduledFuture.create();
147    }
148
149    @Override
150    public ListenableScheduledFuture<?> scheduleWithFixedDelay(
151        Runnable command, long initialDelay, long delay, TimeUnit unit) {
152      return NeverScheduledFuture.create();
153    }
154
155    private static class NeverScheduledFuture<V> extends AbstractFuture<V>
156        implements ListenableScheduledFuture<V> {
157
158      static <V> NeverScheduledFuture<V> create() {
159        return new NeverScheduledFuture<>();
160      }
161
162      @Override
163      public long getDelay(TimeUnit unit) {
164        return Long.MAX_VALUE;
165      }
166
167      @Override
168      public int compareTo(Delayed other) {
169        return Longs.compare(getDelay(NANOSECONDS), other.getDelay(NANOSECONDS));
170      }
171    }
172  }
173}