Skip to content

Instantly share code, notes, and snippets.

@thekeenant
Last active May 23, 2019 23:02
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thekeenant/883985b94c81e92e97ebd3c9e6ea1664 to your computer and use it in GitHub Desktop.
Save thekeenant/883985b94c81e92e97ebd3c9e6ea1664 to your computer and use it in GitHub Desktop.
An implementation of ScheduledExecutorService for LibGDX which executes tasks on the main game thread.
import com.badlogic.gdx.Gdx;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* A {@link ScheduledExecutorService} implementation that executes operations on the game loop
* thread using {@link com.badlogic.gdx.Application#postRunnable(Runnable)} via {@link Gdx#app}
* and a delegated scheduled executor service.
*/
public class GdxScheduledExecutorService implements ScheduledExecutorService {
private final ScheduledExecutorService delegate;
public GdxScheduledExecutorService(ScheduledExecutorService delegate) {
this.delegate = delegate;
}
/**
* Creates a new {@link GdxScheduledExecutorService} with a thread pool as the delegate.
* @param corePoolSize the number of threads to keep in the pool
* @return the new executor service
*/
public static GdxScheduledExecutorService create(int corePoolSize) {
return new GdxScheduledExecutorService(Executors.newScheduledThreadPool(corePoolSize));
}
@Override
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
return delegate.schedule(() -> runTask(command), delay, unit);
}
@Override
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
return delegate.schedule(() -> runCallable(callable), delay, unit);
}
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
return delegate.scheduleAtFixedRate(() -> runTask(command), initialDelay, period, unit);
}
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
return delegate.scheduleWithFixedDelay(() -> runTask(command), initialDelay, delay, unit);
}
@Override
public void shutdown() {
delegate.shutdown();
}
@Override
public List<Runnable> shutdownNow() {
return delegate.shutdownNow();
}
@Override
public boolean isShutdown() {
return delegate.isShutdown();
}
@Override
public boolean isTerminated() {
return delegate.isTerminated();
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
return delegate.awaitTermination(timeout, unit);
}
@Override
public <T> Future<T> submit(Callable<T> task) {
return delegate.submit(() -> runCallable(task));
}
@Override
public <T> Future<T> submit(Runnable task, T result) {
return delegate.submit(() -> runTask(task), result);
}
@Override
public Future<?> submit(Runnable task) {
return delegate.submit(() -> runTask(task));
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
return delegate.invokeAll(gdxTasks(tasks));
}
@Override
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout,
TimeUnit unit) throws InterruptedException {
return delegate.invokeAll(gdxTasks(tasks), timeout, unit);
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
return delegate.invokeAny(gdxTasks(tasks));
}
@Override
public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return delegate.invokeAny(gdxTasks(tasks), timeout, unit);
}
@Override
public void execute(Runnable command) {
delegate.execute(() -> runTask(command));
}
private void runTask(Runnable command) {
CountDownLatch lock = new CountDownLatch(1);
Gdx.app.postRunnable(() -> {
command.run();
lock.countDown();
});
try {
lock.await();
}
catch (InterruptedException e) {
// ignored
}
}
private <V> V runCallable(Callable<V> callable) throws Exception {
AtomicReference<V> result = new AtomicReference<>();
AtomicReference<Exception> exception = new AtomicReference<>();
CountDownLatch lock = new CountDownLatch(1);
Gdx.app.postRunnable(() -> {
try {
result.set(callable.call());
}
catch (Exception e) {
exception.set(e);
}
lock.countDown();
});
lock.await();
if (exception.get() != null) {
throw exception.get();
}
return result.get();
}
private <T> List<? extends Callable<T>> gdxTasks(Collection<? extends Callable<T>> tasks) {
return tasks.stream()
.map(task -> (Callable<T>) () -> runCallable(task))
.collect(Collectors.toList());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment