com.github.phantomthief.concurrent.MoreFutures Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of more-lambdas Show documentation
Show all versions of more-lambdas Show documentation
Some useful lambda implements for Java 8.
package com.github.phantomthief.concurrent;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.util.concurrent.Uninterruptibles.getUninterruptibly;
import static java.lang.System.nanoTime;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.time.Duration;
import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.phantomthief.util.ThrowableConsumer;
import com.github.phantomthief.util.ThrowableFunction;
import com.github.phantomthief.util.ThrowableRunnable;
import com.google.common.util.concurrent.AbstractFuture;
import com.google.common.util.concurrent.AsyncFunction;
import com.google.common.util.concurrent.ExecutionError;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.UncheckedExecutionException;
import com.google.common.util.concurrent.UncheckedTimeoutException;
/**
* @author w.vela
* Created on 2018-06-25.
*/
public class MoreFutures {
private static final Logger logger = LoggerFactory.getLogger(MoreFutures.class);
/**
* @throws UncheckedTimeoutException if timeout occurred.
* @throws java.util.concurrent.CancellationException if task was canceled.
* @throws ExecutionError if a {@link Error} occurred.
* @throws UncheckedExecutionException if a normal Exception occurred.
*/
public static T getUnchecked(@Nonnull Future extends T> future,
@Nonnull Duration duration) {
checkNotNull(duration);
return getUnchecked(future, duration.toNanos(), NANOSECONDS);
}
/**
* @throws UncheckedTimeoutException if timeout occurred.
* @throws java.util.concurrent.CancellationException if task was canceled.
* @throws ExecutionError if a {@link Error} occurred.
* @throws UncheckedExecutionException if a normal Exception occurred.
*/
public static T getUnchecked(@Nonnull Future extends T> future, @Nonnegative long timeout,
@Nonnull TimeUnit unit) {
return getUnchecked(future, timeout, unit, false);
}
/**
* @throws UncheckedTimeoutException if timeout occurred.
* @throws java.util.concurrent.CancellationException if task was canceled.
* @throws ExecutionError if a {@link Error} occurred.
* @throws UncheckedExecutionException if a normal Exception occurred.
*/
public static T getUnchecked(@Nonnull Future extends T> future, @Nonnegative long timeout,
@Nonnull TimeUnit unit, boolean cancelOnTimeout) {
checkArgument(timeout > 0);
checkNotNull(future);
try {
return getUninterruptibly(future, timeout, unit);
} catch (ExecutionException e) {
Throwable cause = e.getCause();
if (cause instanceof Error) {
throw new ExecutionError((Error) cause);
} else {
throw new UncheckedExecutionException(cause);
}
} catch (TimeoutException e) {
if (cancelOnTimeout) {
future.cancel(false);
}
throw new UncheckedTimeoutException(e);
}
}
/**
* @see #tryWait(Iterable, long, TimeUnit)
*
* @throws TryWaitFutureUncheckedException if not all calls are successful.
*/
@Nonnull
public static , V> Map tryWait(@Nonnull Iterable futures,
@Nonnull Duration duration) throws TryWaitFutureUncheckedException {
checkNotNull(futures);
checkNotNull(duration);
return tryWait(futures, duration.toNanos(), NANOSECONDS);
}
/**
* A typical usage:
* {@code
* // a fail-safe example
* List> list = doSomeAsyncTasks();
* Map, User> success;
* try {
* success = tryWait(list, 1, SECONDS);
* } catch (TryWaitUncheckedException e) {
* success = e.getSuccess(); // there are still some success
* }
*
* // a fail-fast example
* List> list = doSomeAsyncTasks();
* // don't try/catch the exception it throws.
* Map, User> success = tryWait(list, 1, SECONDS);
*
}
*
* @throws TryWaitUncheckedException if not all calls are successful.
*/
@Nonnull
public static , V> Map tryWait(@Nonnull Iterable futures,
@Nonnegative long timeout, @Nonnull TimeUnit unit)
throws TryWaitFutureUncheckedException {
checkNotNull(futures);
checkArgument(timeout > 0);
checkNotNull(unit);
return tryWait(futures, timeout, unit, it -> it, TryWaitFutureUncheckedException::new);
}
/**
* @see #tryWait(Iterable, long, TimeUnit, ThrowableFunction)
*
* @throws TryWaitUncheckedException if not all calls are successful.
*/
@Nonnull
public static Map tryWait(@Nonnull Iterable keys,
@Nonnull Duration duration, @Nonnull ThrowableFunction, X> asyncFunc)
throws X, TryWaitUncheckedException {
checkNotNull(keys);
checkNotNull(duration);
checkNotNull(asyncFunc);
return tryWait(keys, duration.toNanos(), NANOSECONDS, asyncFunc);
}
/**
* A typical usage:
* {@code
* // a fail-safe example
* List list = getSomeIds();
* Map success;
* try {
* success = tryWait(list, 1, SECONDS, id -> executor.submit(() -> retrieve(id)));
* } catch (TryWaitUncheckedException e) {
* success = e.getSuccess(); // there are still some success
* }
*
* // a fail-fast example
* List list = getSomeIds();
* // don't try/catch the exception it throws.
* Map success = tryWait(list, 1, SECONDS, id -> executor.submit(() -> retrieve(id)));
*
}
*
* @throws TryWaitUncheckedException if not all calls are successful.
*/
@Nonnull
public static Map tryWait(@Nonnull Iterable keys,
@Nonnegative long timeout, @Nonnull TimeUnit unit,
@Nonnull ThrowableFunction, X> asyncFunc)
throws X, TryWaitUncheckedException {
return tryWait(keys, timeout, unit, asyncFunc, TryWaitUncheckedException::new);
}
@Nonnull
private static Map tryWait(@Nonnull Iterable keys,
@Nonnegative long timeout, @Nonnull TimeUnit unit,
@Nonnull ThrowableFunction, X> asyncFunc,
@Nonnull Function throwing) throws X {
checkNotNull(keys);
checkArgument(timeout > 0);
checkNotNull(unit);
checkNotNull(asyncFunc);
Map, V> successMap = new LinkedHashMap<>();
Map, Throwable> failMap = new LinkedHashMap<>();
Map, TimeoutException> timeoutMap = new LinkedHashMap<>();
Map, CancellationException> cancelMap = new LinkedHashMap<>();
long remainingNanos = unit.toNanos(timeout);
long end = nanoTime() + remainingNanos;
Map, K> futureKeyMap = new IdentityHashMap<>();
for (K key : keys) {
checkNotNull(key);
Future future = asyncFunc.apply(key);
checkNotNull(future);
futureKeyMap.put(future, key);
if (remainingNanos <= 0) {
waitAndCollect(successMap, failMap, timeoutMap, cancelMap, future, 1L);
continue;
}
waitAndCollect(successMap, failMap, timeoutMap, cancelMap, future, remainingNanos);
remainingNanos = end - nanoTime();
}
TryWaitResult result = new TryWaitResult<>(successMap, failMap, timeoutMap, cancelMap,
futureKeyMap);
if (failMap.isEmpty() && timeoutMap.isEmpty() && cancelMap.isEmpty()) {
return result.getSuccess();
} else {
throw throwing.apply(result);
}
}
private static void waitAndCollect(Map, T> successMap,
Map, Throwable> failMap,
Map, TimeoutException> timeoutMap,
Map, CancellationException> cancelMap, Future extends T> future,
long thisWait) {
try {
T t = getUninterruptibly(future, thisWait, NANOSECONDS);
successMap.put(future, t);
} catch (CancellationException e) {
cancelMap.put(future, e);
} catch (TimeoutException e) {
timeoutMap.put(future, e);
} catch (ExecutionException e) {
failMap.put(future, e.getCause());
} catch (Throwable e) {
failMap.put(future, e);
}
}
/**
* @param task any exception throwing would cancel the task. user should swallow exceptions by self.
* @param executor all task would be stopped after executor has been marked shutting down.
* @return a future that can cancel the task.
*/
public static Future> scheduleWithDynamicDelay(@Nonnull ScheduledExecutorService executor,
@Nullable Duration initDelay, @Nonnull Scheduled task) {
checkNotNull(executor);
checkNotNull(task);
AtomicBoolean canceled = new AtomicBoolean(false);
AbstractFuture> future = new AbstractFuture
© 2015 - 2024 Weber Informatics LLC | Privacy Policy