org.cobraparser.util.SimpleThreadPool Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Cobra Show documentation
Show all versions of Cobra Show documentation
Cobra is the rendering engine designed for LoboBrowser
package org.cobraparser.util;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* A thread pool that allows cancelling all running tasks without shutting down
* the thread pool.
*/
public class SimpleThreadPool {
private static final Logger logger = Logger.getLogger(SimpleThreadPool.class.getName());
private final LinkedList taskList = new LinkedList<>();
private final Set runningSet = new HashSet<>();
private final int minThreads;
private final int maxThreads;
private final String name;
private final int idleAliveMillis;
private final Object taskMonitor = new Object();
private final ThreadGroup threadGroup;
private int numThreads = 0;
private int numIdleThreads = 0;
private int threadNumber = 0;
public SimpleThreadPool(final String name, final int minShrinkToThreads, final int maxThreads, final int idleAliveMillis) {
this.minThreads = minShrinkToThreads;
this.maxThreads = maxThreads;
this.idleAliveMillis = idleAliveMillis;
this.name = name;
// Thread group needed so item requests
// don't get assigned sub-thread groups.
// TODO: Thread group needs to be thought through. It's retained in
// memory, and we need to return the right one in the GUI thread as well.
this.threadGroup = null; // new ThreadGroup(name);
}
public void schedule(final SimpleThreadPoolTask task) {
if (task == null) {
throw new IllegalArgumentException("null task");
}
final Object monitor = this.taskMonitor;
synchronized (monitor) {
if (this.numIdleThreads == 0) {
this.addThreadImpl();
}
this.taskList.add(task);
monitor.notify();
}
}
public void cancel(final SimpleThreadPoolTask task) {
synchronized (this.taskMonitor) {
this.taskList.remove(task);
}
task.cancel();
}
private void addThreadImpl() {
if (this.numThreads < this.maxThreads) {
final Thread t = new Thread(this.threadGroup, new ThreadRunnable(), this.name + this.threadNumber++);
t.setDaemon(true);
t.start();
this.numThreads++;
}
}
/**
* Cancels all waiting tasks and any currently running task.
*/
public void cancelAll() {
synchronized (this.taskMonitor) {
this.taskList.clear();
final Iterator i = this.runningSet.iterator();
while (i.hasNext()) {
i.next().cancel();
}
}
}
private class ThreadRunnable implements Runnable {
public void run() {
final Object monitor = taskMonitor;
final LinkedList tl = taskList;
final Set rs = runningSet;
final int iam = idleAliveMillis;
SimpleThreadPoolTask task = null;
for (;;) {
try {
synchronized (monitor) {
if (task != null) {
rs.remove(task);
}
numIdleThreads++;
try {
long waitBase = System.currentTimeMillis();
INNER: while (tl.isEmpty()) {
final long maxWait = iam - (System.currentTimeMillis() - waitBase);
if (maxWait <= 0) {
if (numThreads > minThreads) {
// Should be only way to exit thread.
numThreads--;
return;
} else {
waitBase = System.currentTimeMillis();
continue INNER;
}
}
monitor.wait(maxWait);
}
} finally {
numIdleThreads--;
}
task = taskList.removeFirst();
rs.add(task);
}
final Thread currentThread = Thread.currentThread();
final String baseName = currentThread.getName();
try {
try {
currentThread.setName(baseName + ":" + task.toString());
} catch (final Exception thrown) {
logger.log(Level.WARNING, "run(): Unable to set task name.", thrown);
}
try {
task.run();
} catch (final Exception thrown) {
logger.log(Level.SEVERE, "run(): Error in task: " + task + ".", thrown);
}
} finally {
currentThread.setName(baseName);
}
} catch (final Exception thrown) {
logger.log(Level.SEVERE, "run(): Error in thread pool: " + SimpleThreadPool.this.name + ".", thrown);
}
}
}
}
}