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