org.opentcs.common.SameThreadExecutorService Maven / Gradle / Ivy
The newest version!
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.common;
import static java.util.Objects.requireNonNull;
import static org.opentcs.util.Assertions.checkArgument;
import static org.opentcs.util.Assertions.checkState;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;
/**
* An executor service that executes all task directly on the same thread.
*/
public class SameThreadExecutorService
implements
ExecutorService {
private boolean shutdown;
public SameThreadExecutorService() {
shutdown = false;
}
@Override
public void shutdown() {
shutdown = true;
}
@Override
public List shutdownNow() {
shutdown = true;
return List.of();
}
@Override
public boolean isShutdown() {
return shutdown;
}
@Override
public boolean isTerminated() {
return shutdown;
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
// Calling `awaitTermination` before calling shutdown is not a valid use for an executor
// service and therefore should throw an exeception.
checkState(shutdown, "Awaiting termination before shutdown was called");
return true;
}
@Override
public Future submit(Callable task) {
CompletableFuture future = new CompletableFuture<>();
try {
future.complete(task.call());
}
catch (Exception e) {
future.completeExceptionally(e);
}
return future;
}
@Override
public Future submit(Runnable task, T result) {
return this.submit(() -> {
task.run();
return result;
});
}
@Override
public Future> submit(Runnable task) {
return this.submit(task, null);
}
@Override
public List> invokeAll(Collection extends Callable> tasks)
throws InterruptedException {
return tasks.stream()
.map(task -> submit(task))
.collect(Collectors.toList());
}
@Override
public List> invokeAll(
Collection extends Callable> tasks,
long timeout,
TimeUnit unit
)
throws InterruptedException {
return invokeAll(tasks);
}
@Override
public T invokeAny(Collection extends Callable> tasks)
throws InterruptedException,
ExecutionException {
requireNonNull(tasks, "tasks");
checkArgument(tasks.isEmpty(), "tasks is empty");
if (tasks.stream().anyMatch(task -> task == null)) {
throw new NullPointerException("At least one task given is null");
}
// This implementation interprets the method documentation so that all tasks are started
// before the result of the first successful one is returned.
// Since all task are executed directly on the same thread, all task will finish before this
// method returns the value of any successful task.
List> futures = invokeAll(tasks);
for (Future future : futures) {
try {
return future.get();
}
catch (InterruptedException e) {
throw e;
}
catch (Exception e) {
// any other exception thrown by the future is ignored
}
}
throw new ExecutionException(new Exception("None of the provided task sucessfully terminated"));
}
@Override
public T invokeAny(Collection extends Callable> tasks, long timeout, TimeUnit unit)
throws InterruptedException,
ExecutionException,
TimeoutException {
return invokeAny(tasks);
}
@Override
public void execute(Runnable command) {
command.run();
}
}