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

org.kernelab.basis.ThreadPoolDirector Maven / Gradle / Ivy

There is a newer version: 0.0.19-RELEASE
Show newest version
package org.kernelab.basis;

import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadPoolDirector extends ThreadPoolExecutor
{
	public static class AbortPolicy implements RejectedExecutionHandler
	{
		public AbortPolicy()
		{
		}

		public void rejectedExecution(Runnable r, ThreadPoolExecutor e)
		{
			throw new RejectedExecutionException();
		}
	}

	public static class CallerRunsPolicy implements RejectedExecutionHandler
	{
		public CallerRunsPolicy()
		{
		}

		public void rejectedExecution(Runnable r, ThreadPoolExecutor e)
		{
			if (!e.isShutdown())
			{
				r.run();
			}
		}
	}

	public static class DiscardOldestPolicy implements RejectedExecutionHandler
	{
		public DiscardOldestPolicy()
		{
		}

		public void rejectedExecution(Runnable r, ThreadPoolExecutor e)
		{
			if (!e.isShutdown())
			{
				e.getQueue().poll();
				e.execute(r);
			}
		}
	}

	public static class DiscardPolicy implements RejectedExecutionHandler
	{
		public DiscardPolicy()
		{
		}

		public void rejectedExecution(Runnable r, ThreadPoolExecutor e)
		{
		}
	}

	private class Worker implements Runnable
	{
		private final ReentrantLock	runLock	= new ReentrantLock();

		private Runnable			firstTask;

		volatile long				completedTasks;

		Thread						thread;

		Worker(Runnable firstTask)
		{
			this.firstTask = firstTask;
		}

		void interruptIfIdle()
		{
			final ReentrantLock runLock = this.runLock;
			if (runLock.tryLock())
			{
				try
				{
					if (thread != Thread.currentThread())
					{
						thread.interrupt();
					}
				}
				finally
				{
					runLock.unlock();
				}
			}
		}

		void interruptNow()
		{
			thread.interrupt();
		}

		boolean isActive()
		{
			return runLock.isLocked();
		}

		public void run()
		{
			try
			{
				Runnable task = firstTask;
				firstTask = null;
				while (task != null || (task = takeTask()) != null)
				{
					runTask(task);
					task = null;
				}
			}
			catch (InterruptedException ie)
			{
			}
			finally
			{
				workerDone(this);
			}
		}

		private void runTask(Runnable task)
		{
			final ReentrantLock runLock = this.runLock;
			runLock.lock();
			try
			{
				if (runState == STOP)
				{
					return;
				}

				Thread.interrupted();
				boolean ran = false;
				beforeExecute(thread, task);
				try
				{
					task.run();
					ran = true;
					afterExecute(task, null);
					++completedTasks;
				}
				catch (RuntimeException ex)
				{
					if (!ran)
					{
						afterExecute(task, ex);
					}
					throw ex;
				}
			}
			finally
			{
				runLock.unlock();
			}
		}
	}

	private static final Runnable[]					EMPTY_RUNNABLE_ARRAY	= new Runnable[0];

	private static final RuntimePermission			shutdownPerm			= new RuntimePermission("modifyThread");

	static final int								RUNNING					= 0;

	static final int								SHUTDOWN				= 1;

	static final int								STOP					= 2;

	static final int								TERMINATED				= 3;

	private static final RejectedExecutionHandler	defaultHandler			= new AbortPolicy();

	private final BlockingQueue			workQueue;

	private final ReentrantLock						mainLock				= new ReentrantLock();

	private final Condition							termination				= mainLock.newCondition();

	private final HashSet					workers					= new HashSet();

	private volatile long							keepAliveTime;

	private volatile int							corePoolSize;

	private volatile int							maximumPoolSize;

	private volatile int							poolSize;

	volatile int									runState;

	private volatile RejectedExecutionHandler		handler;

	private volatile ThreadFactory					threadFactory;

	private int										largestPoolSize;

	private long									completedTaskCount;

	public ThreadPoolDirector(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue workQueue)
	{
		this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(),
				defaultHandler);
	}

	public ThreadPoolDirector(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue workQueue, RejectedExecutionHandler handler)
	{
		this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), handler);
	}

	public ThreadPoolDirector(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue workQueue, ThreadFactory threadFactory)
	{
		this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, defaultHandler);
	}

	public ThreadPoolDirector(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit,
			BlockingQueue workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler)
	{
		super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);

		if (corePoolSize < 0 || maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0)
		{
			throw new IllegalArgumentException();
		}
		if (workQueue == null || threadFactory == null || handler == null)
		{
			throw new NullPointerException();
		}
		this.corePoolSize = corePoolSize;
		this.maximumPoolSize = maximumPoolSize;
		this.workQueue = workQueue;
		this.keepAliveTime = unit.toNanos(keepAliveTime);
		this.threadFactory = threadFactory;
		this.handler = handler;
	}

	private boolean addIfUnderCorePoolSize(Runnable firstTask)
	{
		Thread t = null;
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			if (poolSize < corePoolSize)
			{
				t = addThread(firstTask);
			}
		}
		finally
		{
			mainLock.unlock();
		}
		if (t == null)
		{
			return false;
		}
		t.start();
		return true;
	}

	private Runnable addIfUnderMaximumPoolSize(Runnable firstTask)
	{
		Thread t = null;
		Runnable next = null;
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			if (poolSize < maximumPoolSize)
			{
				next = workQueue.poll();
				if (next == null)
				{
					next = firstTask;
				}
				t = addThread(next);
			}
		}
		finally
		{
			mainLock.unlock();
		}
		if (t == null)
		{
			return null;
		}
		t.start();
		return next;
	}

	private Thread addThread(Runnable firstTask)
	{
		Worker w = new Worker(firstTask);
		Thread t = threadFactory.newThread(w);
		if (t != null)
		{
			w.thread = t;
			workers.add(w);
			int nt = ++poolSize;
			if (nt > largestPoolSize)
			{
				largestPoolSize = nt;
			}
		}
		return t;
	}

	protected void afterExecute(Runnable r, Throwable t)
	{
	}

	public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException
	{
		long nanos = unit.toNanos(timeout);
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			while (true)
			{
				if (runState == TERMINATED)
				{
					return true;
				}
				if (nanos <= 0)
				{
					return false;
				}
				nanos = termination.awaitNanos(nanos);
			}
		}
		finally
		{
			mainLock.unlock();
		}
	}

	protected void beforeExecute(Thread t, Runnable r)
	{
	}

	void doReject(Runnable command)
	{
		handler.rejectedExecution(command, this);
	}

	public void execute(Runnable command)
	{
		if (command == null)
		{
			throw new NullPointerException();
		}
		while (true)
		{
			if (runState != RUNNING)
			{
				doReject(command);
				return;
			}

			if (poolSize < corePoolSize && addIfUnderCorePoolSize(command))
			{
				return;
			}
			if (workQueue.offer(command))
			{
				return;
			}
			Runnable r = addIfUnderMaximumPoolSize(command);
			if (r == command)
			{
				return;
			}
			if (r == null)
			{
				doReject(command);
				return;
			}
		}
	}

	protected void finalize()
	{
		shutdown();
	}

	public int getActiveCount()
	{
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			int n = 0;
			for (Worker w : workers)
			{
				if (w.isActive())
				{
					++n;
				}
			}
			return n;
		}
		finally
		{
			mainLock.unlock();
		}
	}

	public long getCompletedTaskCount()
	{
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			long n = completedTaskCount;
			for (Worker w : workers)
			{
				n += w.completedTasks;
			}
			return n;
		}
		finally
		{
			mainLock.unlock();
		}
	}

	public int getCorePoolSize()
	{
		return corePoolSize;
	}

	public long getKeepAliveTime(TimeUnit unit)
	{
		return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
	}

	public int getLargestPoolSize()
	{
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			return largestPoolSize;
		}
		finally
		{
			mainLock.unlock();
		}
	}

	public int getMaximumPoolSize()
	{
		return maximumPoolSize;
	}

	public int getPoolSize()
	{
		return poolSize;
	}

	public BlockingQueue getQueue()
	{
		return workQueue;
	}

	public RejectedExecutionHandler getRejectedExecutionHandler()
	{
		return handler;
	}

	public long getTaskCount()
	{
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			long n = completedTaskCount;
			for (Worker w : workers)
			{
				n += w.completedTasks;
				if (w.isActive())
				{
					++n;
				}
			}
			return n + workQueue.size();
		}
		finally
		{
			mainLock.unlock();
		}
	}

	public ThreadFactory getThreadFactory()
	{
		return threadFactory;
	}

	public boolean isShutdown()
	{
		return runState != RUNNING;
	}

	public boolean isTerminated()
	{
		return runState == TERMINATED;
	}

	public boolean isTerminating()
	{
		return runState == STOP;
	}

	public int prestartAllCoreThreads()
	{
		int n = 0;
		while (addIfUnderCorePoolSize(null))
		{
			++n;
		}
		return n;
	}

	public boolean prestartCoreThread()
	{
		return addIfUnderCorePoolSize(null);
	}

	public void purge()
	{
		try
		{
			Iterator it = getQueue().iterator();
			while (it.hasNext())
			{
				Runnable r = it.next();
				if (r instanceof Future)
				{
					Future c = (Future) r;
					if (c.isCancelled())
					{
						it.remove();
					}
				}
			}
		}
		catch (ConcurrentModificationException ex)
		{
			return;
		}
	}

	public boolean remove(Runnable task)
	{
		return getQueue().remove(task);
	}

	public void setCorePoolSize(int corePoolSize)
	{
		if (corePoolSize < 0)
		{
			throw new IllegalArgumentException();
		}
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			int extra = this.corePoolSize - corePoolSize;
			this.corePoolSize = corePoolSize;
			if (extra < 0)
			{
				int n = workQueue.size();
				while (extra++ < 0 && n-- > 0 && poolSize < corePoolSize)
				{
					Thread t = addThread(null);
					if (t != null)
					{
						t.start();
					}
					else
					{
						break;
					}
				}
			}
			else if (extra > 0 && poolSize > corePoolSize)
			{
				try
				{
					Iterator it = workers.iterator();
					while (it.hasNext() && extra-- > 0 && poolSize > corePoolSize)
					{
						it.next().interruptIfIdle();
					}
				}
				catch (SecurityException ignore)
				{
				}
			}
		}
		finally
		{
			mainLock.unlock();
		}
	}

	public void setKeepAliveTime(long time, TimeUnit unit)
	{
		if (time < 0)
		{
			throw new IllegalArgumentException();
		}
		this.keepAliveTime = unit.toNanos(time);
	}

	public void setMaximumPoolSize(int maximumPoolSize)
	{
		if (maximumPoolSize < 0 || maximumPoolSize < corePoolSize)
		{
			throw new IllegalArgumentException();
		}
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			int extra = this.maximumPoolSize - maximumPoolSize;
			this.maximumPoolSize = maximumPoolSize;
			if (extra > 0 && poolSize > maximumPoolSize)
			{
				try
				{
					Iterator it = workers.iterator();
					while (it.hasNext() && extra > 0 && poolSize > maximumPoolSize)
					{
						it.next().interruptIfIdle();
						--extra;
					}
				}
				catch (SecurityException ignore)
				{
				}
			}
		}
		finally
		{
			mainLock.unlock();
		}
	}

	public void setRejectedExecutionHandler(RejectedExecutionHandler handler)
	{
		if (handler == null)
		{
			throw new NullPointerException();
		}
		this.handler = handler;
	}

	public void setThreadFactory(ThreadFactory threadFactory)
	{
		if (threadFactory == null)
		{
			throw new NullPointerException();
		}
		this.threadFactory = threadFactory;
	}

	public void shutdown()
	{
		SecurityManager security = System.getSecurityManager();
		if (security != null)
		{
			java.security.AccessController.checkPermission(shutdownPerm);
		}

		boolean fullyTerminated = false;
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			if (workers.size() > 0)
			{
				if (security != null)
				{
					for (Worker w : workers)
					{
						security.checkAccess(w.thread);
					}
				}

				int state = runState;
				if (state == RUNNING)
				{
					runState = SHUTDOWN;
				}

				try
				{
					for (Worker w : workers)
					{
						w.interruptIfIdle();
					}
				}
				catch (SecurityException se)
				{
					runState = state;
					throw se;
				}
			}
			else
			{
				fullyTerminated = true;
				runState = TERMINATED;
				termination.signalAll();
			}
		}
		finally
		{
			mainLock.unlock();
		}
		if (fullyTerminated)
		{
			terminated();
		}
	}

	public List shutdownNow()
	{
		SecurityManager security = System.getSecurityManager();
		if (security != null)
		{
			java.security.AccessController.checkPermission(shutdownPerm);
		}

		boolean fullyTerminated = false;
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			if (workers.size() > 0)
			{
				if (security != null)
				{
					for (Worker w : workers)
					{
						security.checkAccess(w.thread);
					}
				}

				int state = runState;
				if (state != TERMINATED)
				{
					runState = STOP;
				}
				try
				{
					for (Worker w : workers)
					{
						w.interruptNow();
					}
				}
				catch (SecurityException se)
				{
					runState = state;
					throw se;
				}
			}
			else
			{
				fullyTerminated = true;
				runState = TERMINATED;
				termination.signalAll();
			}
		}
		finally
		{
			mainLock.unlock();
		}
		if (fullyTerminated)
		{
			terminated();
		}
		return Arrays.asList(workQueue.toArray(EMPTY_RUNNABLE_ARRAY));
	}

	Runnable takeTask() throws InterruptedException
	{
		while (true)
		{
			switch (runState)
			{
				case RUNNING:
				{
					if (poolSize <= corePoolSize)
					{
						return workQueue.take();
					}

					long timeout = keepAliveTime;
					if (timeout <= 0)
					{
						return null;
					}
					Runnable r = workQueue.poll(timeout, TimeUnit.NANOSECONDS);
					if (r != null)
					{
						return r;
					}
					if (poolSize > corePoolSize)
					{
						return null;
					}
					break;
				}

				case SHUTDOWN:
				{
					Runnable r = workQueue.poll();
					if (r != null)
					{
						return r;
					}

					if (workQueue.isEmpty())
					{
						wakeupIdleWorkers();
						return null;
					}

					try
					{
						return workQueue.take();
					}
					catch (InterruptedException ignore)
					{
					}
					break;
				}

				case STOP:
					return null;
			}
		}
	}

	protected void terminated()
	{
	}

	void wakeupIdleWorkers()
	{
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			for (Worker w : workers)
			{
				w.interruptIfIdle();
			}
		}
		finally
		{
			mainLock.unlock();
		}
	}

	void workerDone(Worker w)
	{
		final ReentrantLock mainLock = this.mainLock;
		mainLock.lock();
		try
		{
			completedTaskCount += w.completedTasks;
			workers.remove(w);
			if (--poolSize > 0)
			{
				return;
			}

			int state = runState;

			if (state != STOP)
			{
				if (!workQueue.isEmpty())
				{
					if (maximumPoolSize > 0)
					{
						Thread t = addThread(null);
						if (t != null)
						{
							t.start();
						}
					}
					return;
				}

				if (state == RUNNING)
				{
					return;
				}
			}

			termination.signalAll();
			runState = TERMINATED;
		}
		finally
		{
			mainLock.unlock();
		}

		terminated();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy