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