package org.limewire.concurrent; import java.util.Collection; import java.util.List; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import org.limewire.util.Objects; /** * A factory that builds {@link ExecutorService}, {@link ThreadFactory} * and {@link ScheduledExecutorService} objects via static methods. * <p> * <code>ExecutorsHelper</code> differs from {@link Executors} since * <code>ExecutorsHelper</code> returns the thread factory for daemon threads * and creates non-fixed size thread pools. Additionally, * <code>ExecutorsHelper</code> guarantees the returned <code>ExeuctorService * </code> will allow worker threads to expire. On the other hand, * <code>Executors</code> create <code>ExecutorService</code>s whose core-pool * of worker threads never die. */ public class ExecutorsHelper { /** * Creates a new "ProcessingQueue" using * {@link #daemonThreadFactory(String)} as thread factory. * <p> * See {@link #newProcessingQueue(ThreadFactory)}. * * @param name the name of the processing thread that is created * with the daemon thread factory. */ public static ListeningExecutorService newProcessingQueue(String name) { return newProcessingQueue(daemonThreadFactory(name)); } /** * Creates a new "ProcessingQueue". * <p> * A <code>ProcessingQueue</code> is an <code>ExecutorService</code> that * will process all Runnables/Callables sequentially, creating one thread * for processing when it needs it. * <p> * See {@link #newSingleThreadExecutor(ThreadFactory)}. * * @param factory the factory used for creating a new processing thread */ public static ListeningExecutorService newProcessingQueue(ThreadFactory factory) { return unconfigurableExecutorService(newSingleThreadExecutor(factory)); } /** * A ProcessingQueue Executor is an <code>ExecutorService</code> that * processes all Runnables/Callables sequentially, creating one thread * for processing when it needs it. * <p> * This kind of Executor is ideal for long-lived tasks * that require processing rarely. * <p> * If there are no tasks the thread will be terminated after a timeout of * 5 seconds and a new one will be created when necessary. * * @param factory the factory used for creating a new processing thread */ public static ThreadPoolListeningExecutor newSingleThreadExecutor(ThreadFactory factory) { ThreadPoolListeningExecutor tpe = new ThreadPoolListeningExecutor(1, 1, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), factory); tpe.allowCoreThreadTimeOut(true); return tpe; } /** * Creates a new ThreadPool. * The pool is tuned to begin with zero threads and maintain zero threads, * although an unlimited number of threads will be created to handle * the tasks. Each thread is set to linger for a short period of time, * ready to handle new tasks, before the thread terminates. */ public static ListeningExecutorService newThreadPool(String name) { return unconfigurableExecutorService( new ThreadPoolListeningExecutor(0, Integer.MAX_VALUE, 5L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), daemonThreadFactory(name))); } /** * Creates a new ThreadPool. * The pool is tuned to begin with zero threads and maintain zero threads, * although an unlimited number of threads will be created to handle * the tasks. Each thread is set to linger for a short period of time, * ready to handle new tasks, before the thread terminates. * * @param factory the factory used for creating a new processing thread */ public static ListeningExecutorService newThreadPool(ThreadFactory factory) { return unconfigurableExecutorService( new ThreadPoolListeningExecutor(0, Integer.MAX_VALUE, 5L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), factory)); } /** * Creates a new ThreadPool with the maximum number of available threads. * Items added while no threads are available to process them will wait * until an executing item is finished and then be processed. */ public static ListeningExecutorService newFixedSizeThreadPool(int size, String name) { ThreadPoolListeningExecutor tpe = new ThreadPoolListeningExecutor(size, size, 5L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), daemonThreadFactory(name)); tpe.allowCoreThreadTimeOut(true); return unconfigurableExecutorService(tpe); } /** * Returns an object that delegates all defined {@link * ListeningExecutorService} methods to the given executor, but not any * other methods that might otherwise be accessible using * casts. This provides a way to safely "freeze" configuration and * disallow tuning of a given concrete implementation. * * @return an <tt>ListeningExecutorService</tt> instance * @throws NullPointerException if executor null */ public static ListeningExecutorService unconfigurableExecutorService(ListeningExecutorService es) { return new DelegatedExecutorService(Objects.nonNull(es, "es")); } /** * Returns the default thread factory, using the given name. */ public static ThreadFactory defaultThreadFactory(String name) { return new DefaultThreadFactory(name, false); } /** * Returns the a thread factory of daemon threads, using the given name. */ public static ThreadFactory daemonThreadFactory(String name) { return new DefaultThreadFactory(name, true); } /** A thread factory that can create threads with a name. */ private static class DefaultThreadFactory implements ThreadFactory { /** The name created threads will use. */ private final String name; /** Whether or not the created thread is a daemon thread. */ private final boolean daemon; /** Constructs a thread factory that will created named threads. */ public DefaultThreadFactory(String name, boolean daemon) { this.name = name; this.daemon = daemon; } public Thread newThread(Runnable r) { Thread t = new ManagedThread(r, name); if(daemon) t.setDaemon(true); return t; } } /** * A wrapper class that exposes only the ListeningExecutorService methods * of an ListeningExecutorService implementation. */ private static class DelegatedExecutorService extends AbstractExecutorService implements ListeningExecutorService { private final ListeningExecutorService e; DelegatedExecutorService(ListeningExecutorService executor) { e = executor; } public void execute(Runnable command) { e.execute(command); } public void shutdown() { e.shutdown(); } public List<Runnable> shutdownNow() { return e.shutdownNow(); } public boolean isShutdown() { return e.isShutdown(); } public boolean isTerminated() { return e.isTerminated(); } public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return e.awaitTermination(timeout, unit); } @Override public ListeningFuture<?> submit(Runnable task) { return e.submit(task); } @Override public <T> ListeningFuture<T> submit(Callable<T> task) { return e.submit(task); } @Override public <T> ListeningFuture<T> submit(Runnable task, T result) { return e.submit(task, result); } @Override public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException { return e.invokeAll(tasks); } @Override public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException { return e.invokeAll(tasks, timeout, unit); } @Override public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException { return e.invokeAny(tasks); } @Override public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return e.invokeAny(tasks, timeout, unit); } } }