| /* |
| * Copyright (C) 2012 The Guava Authors |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.google.common.util.concurrent.testing; |
| |
| import com.google.common.annotations.Beta; |
| import com.google.common.annotations.GwtIncompatible; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.primitives.Longs; |
| import com.google.common.util.concurrent.AbstractFuture; |
| import com.google.common.util.concurrent.AbstractListeningExecutorService; |
| import com.google.common.util.concurrent.ListenableScheduledFuture; |
| import com.google.common.util.concurrent.ListeningScheduledExecutorService; |
| import com.google.common.util.concurrent.MoreExecutors; |
| import java.util.List; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.Delayed; |
| import java.util.concurrent.ScheduledFuture; |
| import java.util.concurrent.TimeUnit; |
| |
| /** |
| * Factory methods for {@link ExecutorService} for testing. |
| * |
| * @author Chris Nokleberg |
| * @since 14.0 |
| */ |
| @Beta |
| @GwtIncompatible |
| public final class TestingExecutors { |
| private TestingExecutors() {} |
| |
| /** |
| * Returns a {@link ScheduledExecutorService} that never executes anything. |
| * |
| * <p>The {@code shutdownNow} method of the returned executor always returns an empty list despite |
| * the fact that everything is still technically awaiting execution. The {@code getDelay} method |
| * of any {@link ScheduledFuture} returned by the executor will always return the max long value |
| * instead of the time until the user-specified delay. |
| */ |
| public static ListeningScheduledExecutorService noOpScheduledExecutor() { |
| return new NoOpScheduledExecutorService(); |
| } |
| |
| /** |
| * Creates a scheduled executor service that runs each task in the thread that invokes {@code |
| * execute/submit/schedule}, as in {@link CallerRunsPolicy}. This applies both to individually |
| * submitted tasks and to collections of tasks submitted via {@code invokeAll}, {@code invokeAny}, |
| * {@code schedule}, {@code scheduleAtFixedRate}, and {@code scheduleWithFixedDelay}. In the case |
| * of tasks submitted by {@code invokeAll} or {@code invokeAny}, tasks will run serially on the |
| * calling thread. Tasks are run to completion before a {@code Future} is returned to the caller |
| * (unless the executor has been shutdown). |
| * |
| * <p>The returned executor is backed by the executor returned by {@link |
| * MoreExecutors#newDirectExecutorService} and subject to the same constraints. |
| * |
| * <p>Although all tasks are immediately executed in the thread that submitted the task, this |
| * {@code ExecutorService} imposes a small locking overhead on each task submission in order to |
| * implement shutdown and termination behavior. |
| * |
| * <p>Because of the nature of single-thread execution, the methods {@code scheduleAtFixedRate} |
| * and {@code scheduleWithFixedDelay} are not supported by this class and will throw an |
| * UnsupportedOperationException. |
| * |
| * <p>The implementation deviates from the {@code ExecutorService} specification with regards to |
| * the {@code shutdownNow} method. First, "best-effort" with regards to canceling running tasks is |
| * implemented as "no-effort". No interrupts or other attempts are made to stop threads executing |
| * tasks. Second, the returned list will always be empty, as any submitted task is considered to |
| * have started execution. This applies also to tasks given to {@code invokeAll} or {@code |
| * invokeAny} which are pending serial execution, even the subset of the tasks that have not yet |
| * started execution. It is unclear from the {@code ExecutorService} specification if these should |
| * be included, and it's much easier to implement the interpretation that they not be. Finally, a |
| * call to {@code shutdown} or {@code shutdownNow} may result in concurrent calls to {@code |
| * invokeAll/invokeAny} throwing RejectedExecutionException, although a subset of the tasks may |
| * already have been executed. |
| * |
| * @since 15.0 |
| */ |
| public static SameThreadScheduledExecutorService sameThreadScheduledExecutor() { |
| return new SameThreadScheduledExecutorService(); |
| } |
| |
| private static final class NoOpScheduledExecutorService extends AbstractListeningExecutorService |
| implements ListeningScheduledExecutorService { |
| |
| private volatile boolean shutdown; |
| |
| @Override |
| public void shutdown() { |
| shutdown = true; |
| } |
| |
| @Override |
| public List<Runnable> shutdownNow() { |
| shutdown(); |
| return ImmutableList.of(); |
| } |
| |
| @Override |
| public boolean isShutdown() { |
| return shutdown; |
| } |
| |
| @Override |
| public boolean isTerminated() { |
| return shutdown; |
| } |
| |
| @Override |
| public boolean awaitTermination(long timeout, TimeUnit unit) { |
| return true; |
| } |
| |
| @Override |
| public void execute(Runnable runnable) {} |
| |
| @Override |
| public <V> ListenableScheduledFuture<V> schedule( |
| Callable<V> callable, long delay, TimeUnit unit) { |
| return NeverScheduledFuture.create(); |
| } |
| |
| @Override |
| public ListenableScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { |
| return NeverScheduledFuture.create(); |
| } |
| |
| @Override |
| public ListenableScheduledFuture<?> scheduleAtFixedRate( |
| Runnable command, long initialDelay, long period, TimeUnit unit) { |
| return NeverScheduledFuture.create(); |
| } |
| |
| @Override |
| public ListenableScheduledFuture<?> scheduleWithFixedDelay( |
| Runnable command, long initialDelay, long delay, TimeUnit unit) { |
| return NeverScheduledFuture.create(); |
| } |
| |
| private static class NeverScheduledFuture<V> extends AbstractFuture<V> |
| implements ListenableScheduledFuture<V> { |
| |
| static <V> NeverScheduledFuture<V> create() { |
| return new NeverScheduledFuture<V>(); |
| } |
| |
| @Override |
| public long getDelay(TimeUnit unit) { |
| return Long.MAX_VALUE; |
| } |
| |
| @Override |
| public int compareTo(Delayed other) { |
| return Longs.compare(getDelay(TimeUnit.NANOSECONDS), other.getDelay(TimeUnit.NANOSECONDS)); |
| } |
| } |
| } |
| } |