All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.almende.util.threads.RunQueue Maven / Gradle / Ivy

There is a newer version: 3.1.1
Show newest version
/*
 * Copyright: Almende B.V. (2014), Rotterdam, The Netherlands
 * License: The Apache Software License, Version 2.0
 */
package com.almende.util.threads;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

/**
 * The Class RunQueue. This is our own ThreadPool, with the following behavior:
 * -Unlimited queue
 * -Threadcount based on number of "Running" Threads, excluding "Blocked",
 * "Timed_waiting" and "Waiting" threads from the threadcount.
 * -Approximately nofCPU threads in Running state.
 */
public class RunQueue extends AbstractExecutorService {
	private static final Logger		LOG				= Logger.getLogger(RunQueue.class
															.getName());
	private final Object			terminationLock	= new Object();
	private final Queue		reserve			= new ConcurrentLinkedQueue();
	private final Queue	tasks			= new ConcurrentLinkedQueue();
	private final HashSet	waiting			= new HashSet(8);
	private final Scanner			scanner			= new Scanner();
	private int						nofCores;
	private HashSet			running			= null;
	private boolean					isShutdown		= false;

	private class Scanner extends Thread {
		@Override
		public void run() {
			for (;;) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {}
				if (isShutdown) {
					return;
				}
				scan();
			}
		}
	}

	private class Worker extends Thread {
		final private Object	lock		= new Object();
		private Runnable		task		= null;
		private boolean			isShutdown	= false;

		public boolean runTask(final Runnable task) {
			if (isShutdown) {
				return false;
			}
			synchronized (lock) {
				if (this.task != null) {
					return false;
				}
				this.task = task;
				lock.notify();
			}
			return true;
		}

		@Override
		public void run() {
			for (;;) {
				synchronized (lock) {
					while (task == null) {
						try {
							lock.wait();
						} catch (InterruptedException e) {
							if (isShutdown) {
								return;
							}
						}
					}
					if (!running.contains(this)){
						threadContinue(this);
					}
					task.run();
					task = null;
					
					if (running.size() <= nofCores){
						//Shortcut: Check if there are more tasks available.
						task = tasks.poll();
					}
					if (task == null){
						threadDone(this);
					}
				}
			}
		}
	}

	/**
	 * Instantiates a new run queue.
	 */
	public RunQueue() {
		nofCores = Runtime.getRuntime().availableProcessors();
		running = new HashSet(nofCores);
		scanner.start();
	}

	@Override
	public void shutdown() {
		isShutdown = true;
		scanner.interrupt();
	}

	@Override
	public List shutdownNow() {
		isShutdown = true;
		scanner.interrupt();
		synchronized (running) {
			synchronized (waiting) {
				for (Worker worker : running) {
					worker.isShutdown = true;
					worker.interrupt();
				}
				for (Worker worker : waiting) {
					worker.isShutdown = true;
					worker.interrupt();
				}
			}
		}
		return new ArrayList(tasks);
	}

	@Override
	public boolean isShutdown() {
		return isShutdown;
	}

	@Override
	public boolean isTerminated() {
		return isShutdown && (running.size() == 0 && waiting.size() == 0);
	}

	@Override
	public boolean awaitTermination(final long timeout, final TimeUnit unit)
			throws InterruptedException {
		final long sleepTime = TimeUnit.MILLISECONDS.convert(timeout, unit);
		synchronized (terminationLock) {
			while (!(running.size() == 0 && waiting.size() == 0)) {
				terminationLock.wait(sleepTime);
			}
		}
		return (running.size() == 0 && waiting.size() == 0);
	}

	@Override
	public void execute(final Runnable command) {
		if (isShutdown()) {
			LOG.warning("Execute called after shutdown, dropping command");
			return;
		}
		final Worker thread = getFreeThread();
		if (thread == null || !thread.runTask(command)) {
			tasks.add(command);
		}
	}

	private Worker getFreeThread() {
		if (running.size() >= nofCores) {
			// early out
			return null;
		}
		Worker res = null;
		synchronized (running) {
			if (running.size() < nofCores) {
				synchronized (reserve) {
					res = reserve.poll();
					if (res != null) {
						running.add(res);
						return res;
					}
				}
				res = new Worker();
				res.start();
				running.add(res);
			}
		}
		return res;
	}
	
	private void threadDone(final Worker thread) {
		if (isShutdown()) {
			thread.isShutdown = true;
		}
		if (!thread.isShutdown) {
			if (running.contains(thread) && running.size() <= nofCores) {
				final Runnable task = tasks.poll();
				if (task != null) {
					if (!thread.runTask(task)) {
						tasks.add(task);
					} else {
						return;
					}
				} else {
					synchronized (running) {
						synchronized (reserve) {
							if (reserve.size() < nofCores) {
								running.remove(thread);
								reserve.add(thread);
								return;
							}
						}
					}
				}
			}
		}
		threadTearDown(thread);
		synchronized (terminationLock) {
			terminationLock.notify();
		}
	}

	private void threadWaiting(final Worker thread) {
		synchronized (waiting) {
			waiting.add(thread);
		}
		synchronized (running) {
			running.remove(thread);
		}
	}

	private void threadTearDown(final Worker thread) {
		synchronized (running) {
			running.remove(thread);
		}
		synchronized (waiting) {
			waiting.remove(thread);
		}
		if (!thread.isShutdown) {
			thread.isShutdown = true;
			thread.interrupt();
		}
	}

	private void threadContinue(final Worker thread) {
		if (!running.contains(thread)) {
			synchronized (running) {
				running.add(thread);
			}
		}
		synchronized (waiting) {
			waiting.remove(thread);
		}
	}

	private void scan() {
		final Worker[] runn_arr;
		synchronized (running) {
			runn_arr = running.toArray(new Worker[0]);
		}
		for (final Worker thread : runn_arr) {
			switch (thread.getState()) {
				case TIMED_WAITING:
					// explicit no break
				case WAITING:
					// explicit no break
				case BLOCKED:
					if (thread.task != null) {
						threadWaiting(thread);
					}
					break;
				case TERMINATED:
					threadDone(thread);
					break;
				default:
					break;
			}
		}
		if (tasks.size() > 0) {
			Worker thread = getFreeThread();
			while (tasks.size() > 0 && thread != null) {
				threadDone(thread);
				thread = getFreeThread();
			}
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy