com.swoval.files.Executor Maven / Gradle / Ivy
package com.swoval.files;
import com.swoval.concurrent.ThreadFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* Provides an execution context to run tasks. Exists to allow source interoperability with scala.js
*/
abstract class Executor implements AutoCloseable {
Executor() {}
/**
* Runs the task on a threadHandle.
*
* @param runnable task to run
*/
void run(final java.lang.Runnable runnable) {
run(runnable, Integer.MAX_VALUE);
}
/**
* Runs the task with a given priority.
*
* @param runnable task to run
*/
abstract void run(final java.lang.Runnable runnable, final int priority);
/** Close the executor. All exceptions must be handled by the implementation. */
@Override
public void close() {}
static class ExecutorImpl extends Executor {
private final AtomicBoolean closed = new AtomicBoolean(false);
final ThreadFactory factory;
final ExecutorService service;
final LinkedBlockingQueue consumers = new LinkedBlockingQueue<>();
ExecutorImpl(final ThreadFactory factory, final ExecutorService service) {
this.factory = factory;
this.service = service;
service.submit(
new java.lang.Runnable() {
@Override
public void run() {
boolean stop = false;
while (!stop && !closed.get() && !java.lang.Thread.currentThread().isInterrupted()) {
try {
final PriorityQueue queue = new PriorityQueue<>();
queue.add(consumers.take());
drainRunnables(queue);
while (queue.peek() != null && !stop) {
drainRunnables(queue);
final PriorityRunnable runnable = queue.poll();
assert (runnable != null);
stop = runnable.priority < 0;
try {
runnable.run();
} catch (final Exception e) {
e.printStackTrace();
}
}
} catch (final InterruptedException e) {
stop = true;
}
}
}
});
}
@SuppressWarnings("EmptyCatchBlock")
@Override
public void close() {
if (closed.compareAndSet(false, true)) {
super.close();
synchronized (consumers) {
consumers.clear();
consumers.offer(STOP);
}
service.shutdownNow();
try {
if (!service.awaitTermination(5, TimeUnit.SECONDS)) {
System.err.println("Couldn't close executor");
}
} catch (InterruptedException e) {
}
}
}
@Override
void run(final Runnable runnable, final int priority) {
if (closed.get()) {
new Exception("Tried to submit to closed executor").printStackTrace(System.err);
} else {
synchronized (consumers) {
if (!consumers.offer(new PriorityRunnable(runnable, priority))) {
throw new IllegalStateException(
"Couldn't run task due to full queue (" + consumers.size() + ")");
}
}
}
}
private void drainRunnables(final PriorityQueue queue) {
synchronized (consumers) {
if (consumers.size() > 0) {
final List list = new ArrayList<>();
consumers.drainTo(list);
queue.addAll(list);
}
}
}
}
/**
* Make a new instance of an Executor
*
* @param name The name of the executor threadHandle
* @return Executor
*/
static Executor make(final String name) {
final ThreadFactory factory = new ThreadFactory(name);
final ExecutorService service =
new ThreadPoolExecutor(
1, 1, 0, TimeUnit.SECONDS, new LinkedBlockingQueue(), factory) {
@Override
protected void afterExecute(java.lang.Runnable r, Throwable t) {
super.afterExecute(r, t);
if (t != null) {
System.err.println("Error running: " + r + "\n" + t);
t.printStackTrace(System.err);
}
}
};
return new ExecutorImpl(factory, service);
}
private static final class PriorityRunnable implements Runnable, Comparable {
private final Runnable runnable;
private final int priority;
PriorityRunnable(final Runnable runnable, final int priority) {
this.runnable = runnable;
this.priority = priority < 0 ? priority : 0;
}
@Override
public int compareTo(final PriorityRunnable that) {
return Integer.compare(this.priority, that.priority);
}
@Override
public void run() {
runnable.run();
}
}
private static final PriorityRunnable STOP =
new PriorityRunnable(
new Runnable() {
@Override
public void run() {}
},
-1);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy