com.google.common.util.concurrent.SimpleTimeLimiter Maven / Gradle / Ivy
/*
* Original Guava code is copyright (C) 2015 The Guava Authors.
* Modifications from Guava are copyright (C) 2015 DiffPlug.
*
* 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;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.google.common.annotations.Beta;
import com.google.common.collect.ObjectArrays;
import com.google.common.collect.Sets;
/**
* A TimeLimiter that runs method calls in the background using an
* {@link ExecutorService}. If the time limit expires for a given method call,
* the thread running the call will be interrupted.
*
* @author Kevin Bourrillion
* @since 1.0
*/
@Beta
public final class SimpleTimeLimiter implements TimeLimiter {
private final ExecutorService executor;
/**
* Constructs a TimeLimiter instance using the given executor service to
* execute proxied method calls.
*
* Warning: using a bounded executor
* may be counterproductive! If the thread pool fills up, any time callers
* spend waiting for a thread may count toward their time limit, and in
* this case the call may even time out before the target method is ever
* invoked.
*
* @param executor the ExecutorService that will execute the method calls on
* the target objects; for example, a {@link
* Executors#newCachedThreadPool()}.
*/
public SimpleTimeLimiter(ExecutorService executor) {
this.executor = checkNotNull(executor);
}
/**
* Constructs a TimeLimiter instance using a {@link
* Executors#newCachedThreadPool()} to execute proxied method calls.
*
*
Warning: using a bounded executor may be counterproductive! If
* the thread pool fills up, any time callers spend waiting for a thread may
* count toward their time limit, and in this case the call may even time out
* before the target method is ever invoked.
*/
public SimpleTimeLimiter() {
this(Executors.newCachedThreadPool());
}
@Override
public T newProxy(final T target, Class interfaceType,
final long timeoutDuration, final TimeUnit timeoutUnit) {
checkNotNull(target);
checkNotNull(interfaceType);
checkNotNull(timeoutUnit);
checkArgument(timeoutDuration > 0, "bad timeout: %s", timeoutDuration);
checkArgument(interfaceType.isInterface(),
"interfaceType must be an interface type");
final Set interruptibleMethods = findInterruptibleMethods(interfaceType);
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object obj, final Method method, final Object[] args)
throws Throwable {
Callable