package com.revolsys.parallel; import java.util.concurrent.Callable; import com.revolsys.io.BaseCloseable; import com.revolsys.util.Exceptions; public class SingleThreadExecutor implements BaseCloseable { private final Object callSync = new Object(); private final Object handleSync = new Object(); private Throwable exception; private Object result; private boolean running = true; private Callable<? extends Object> task; private final Thread thread; private final String threadName; public SingleThreadExecutor(final String threadName) { this.threadName = threadName; this.thread = new Thread(this::taskHandler, threadName); this.thread.setDaemon(true); this.thread.start(); } @SuppressWarnings("unchecked") public <V> V call(final Callable<V> task) { if (task != null) { synchronized (this.callSync) { synchronized (this.handleSync) { try { this.task = task; this.handleSync.notifyAll(); this.handleSync.wait(); if (this.exception == null) { return (V)this.result; } else { throw Exceptions.wrap(this.threadName + ": error running task", this.exception); } } catch (final InterruptedException e) { // Ignore } finally { this.task = null; this.result = null; this.exception = null; } } } } return null; } @Override public void close() { if (this.running) { this.running = false; this.thread.interrupt(); } } private void taskHandler() { while (this.running) { synchronized (this.handleSync) { if (this.task == null) { try { this.handleSync.wait(); } catch (final InterruptedException e) { // Ignore } } else { try { this.result = this.task.call(); } catch (final Throwable e) { this.exception = e; } finally { this.task = null; } this.handleSync.notifyAll(); } } } } @Override public String toString() { return this.threadName; } }