package org.compass.core.util.concurrent; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; /** * @author kimchy */ public class ScalingExecutros { /** * Creates a thread pool that creates new threads as needed, but will reuse * previously constructed threads when they are available. Calls to * <tt>execute</tt> will reuse previously constructed threads if * available. If no existing thread is available, a new thread will be * created and added to the pool. No more than <tt>max</tt> threads will * be created. Threads that have not been used for a <tt>keepAlive</tt> * timeout are terminated and removed from the cache. Thus, a pool that * remains idle for long enough will not consume any resources other than * the <tt>min</tt> specified. * * @param min the number of threads to keep in the pool, even if they are * idle. * @param max the maximum number of threads to allow in the pool. * @param keepAliveTime when the number of threads is greater than the min, * this is the maximum time that excess idle threads will wait * for new tasks before terminating (in milliseconds). * @return the newly created thread pool */ public static ExecutorService newScalingThreadPool(int min, int max, long keepAliveTime) { ScalingQueue<Runnable> queue = new ScalingQueue<Runnable>(); ThreadPoolExecutor executor = new ScalingThreadPoolExecutor(min, max, keepAliveTime, TimeUnit.MILLISECONDS, queue); executor.setRejectedExecutionHandler(new ForceQueuePolicy()); queue.setThreadPoolExecutor(executor); return executor; } /** * Creates a thread pool, same as in * {@link #newScalingThreadPool(int, int, long)}, using the provided * ThreadFactory to create new threads when needed. * * @param min the number of threads to keep in the pool, even if they are * idle. * @param max the maximum number of threads to allow in the pool. * @param keepAliveTime when the number of threads is greater than the min, * this is the maximum time that excess idle threads will wait * for new tasks before terminating (in milliseconds). * @param threadFactory the factory to use when creating new threads. * @return the newly created thread pool */ public static ExecutorService newScalingThreadPool(int min, int max, long keepAliveTime, ThreadFactory threadFactory) { ExecutorService executorService = newScalingThreadPool(min, max, keepAliveTime); ((ThreadPoolExecutor) executorService).setThreadFactory(threadFactory); return executorService; } /** * Creates a thread pool similar to that constructed by * {@link #newScalingThreadPool(int, int, long)}, but blocks the call to * <tt>execute</tt> if the queue has reached it's capacity, and all * <tt>max</tt> threads are busy handling requests. * <p> * If the wait time of this queue has elapsed, a * {@link java.util.concurrent.RejectedExecutionException} will be thrown. * * @param min the number of threads to keep in the pool, even if they are * idle. * @param max the maximum number of threads to allow in the pool. * @param keepAliveTime when the number of threads is greater than the min, * this is the maximum time that excess idle threads will wait * for new tasks before terminating (in milliseconds). * @param capacity the fixed capacity of the underlying queue (resembles * backlog). * @param waitTime the wait time (in milliseconds) for space to become * available in the queue. * @return the newly created thread pool */ public static ExecutorService newBlockingThreadPool(int min, int max, long keepAliveTime, int capacity, long waitTime) { ScalingQueue<Runnable> queue = new ScalingQueue<Runnable>(capacity); ThreadPoolExecutor executor = new ScalingThreadPoolExecutor(min, max, keepAliveTime, TimeUnit.MILLISECONDS, queue); executor.setRejectedExecutionHandler(new TimedBlockingPolicy(waitTime)); queue.setThreadPoolExecutor(executor); return executor; } /** * Creates a thread pool, same as in * {@link #newBlockingThreadPool(int, int, long, int, long)}, using the * provided ThreadFactory to create new threads when needed. * * @param min the number of threads to keep in the pool, even if they are * idle. * @param max the maximum number of threads to allow in the pool. * @param keepAliveTime when the number of threads is greater than the min, * this is the maximum time that excess idle threads will wait * for new tasks before terminating (in milliseconds). * @param capacity the fixed capacity of the underlying queue (resembles * backlog). * @param waitTime the wait time (in milliseconds) for space to become * available in the queue. * @param threadFactory the factory to use when creating new threads. * @return the newly created thread pool */ public static ExecutorService newBlockingThreadPool(int min, int max, long keepAliveTime, int capacity, long waitTime, ThreadFactory threadFactory) { ExecutorService executorService = newBlockingThreadPool(min, max, keepAliveTime, capacity, waitTime); ((ThreadPoolExecutor) executorService).setThreadFactory(threadFactory); return executorService; } /** * A priority based thread factory, for all Thread priority constants: * <tt>Thread.MIN_PRIORITY, Thread.NORM_PRIORITY, Thread.MAX_PRIORITY</tt>; * * <p>This factory is used instead of Executers.DefaultThreadFactory to allow * manipulation of priority and thread owner name. * * @param namePrefix a name prefix for this thread * @return a thread factory based on given priority. */ public static ThreadFactory daemonThreadFactory(String namePrefix) { final ThreadFactory f = Executors.defaultThreadFactory(); final String o = namePrefix + "-"; return new ThreadFactory() { public Thread newThread(Runnable r) { Thread t = f.newThread(r); /* * Thread name: owner-pool-N-thread-M, where N is the sequence * number of this factory, and M is the sequence number of the * thread created by this factory. */ t.setName(o + t.getName()); /* override default definition t.setDaemon(false); */ t.setDaemon(true); return t; } }; } /** * A priority based thread factory, for all Thread priority constants: * <tt>Thread.MIN_PRIORITY, Thread.NORM_PRIORITY, Thread.MAX_PRIORITY</tt>; * <p> * This factory is used instead of Executers.DefaultThreadFactory to allow * manipulation of priority and thread owner name. * * @param priority The priority to be assigned to each thread; * can be either <tt>Thread.MIN_PRIORITY, Thread.NORM_PRIORITY</tt> * or Thread.MAX_PRIORITY. * @param namePrefix a name prefix for this thread * @return a thread factory based on given priority. */ public static ThreadFactory priorityThreadFactory(int priority, String namePrefix) { final ThreadFactory f = ScalingExecutros.daemonThreadFactory(namePrefix); final int p = priority; return new ThreadFactory() { public Thread newThread(Runnable r) { Thread t = f.newThread(r); /* override default thread priority of Thread.NORM_PRIORITY */ if (p != Thread.NORM_PRIORITY) t.setPriority(p); return t; } }; } /** * Cannot instantiate. */ private ScalingExecutros() { } }