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

org.jtrim2.executor.ExecutorsEx Maven / Gradle / Ivy

There is a newer version: 2.0.7
Show newest version
package org.jtrim2.executor;

import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.jtrim2.utils.ExceptionHelper;

/**
 * This class contains static helper and factory methods for {@code Executor}s
 * and {@code ExecutorService}s. This class amongst others, allows new executors
 * to be created not provided by {@link java.util.concurrent.Executors}.
 * 

* This class cannot be inherited and instantiated. * *

Thread safety

* Unless otherwise noted, methods of this class are safe to use by multiple * threads concurrently. * *

Synchronization transparency

* Unless otherwise noted, methods of this class are * synchronization transparent. */ public final class ExecutorsEx { private static final RejectedExecutionHandler REJECT_POLICY = ExecutorsEx::discardOnShutdown; private static final long DEFAULT_THREAD_KEEPALIVE_TIME = 1000; /** * Returns a future representing a canceled task. Attempting to retrieve * its result (by a call to one of its {@code get} methods) will cause * an {@link java.util.concurrent.CancellationException} to be thrown. The * future is considered to be not done and canceled, so * {@link Future#cancel(boolean) canceling} it will always succeed. * *

Thread safety

* This method and the methods of the returned {@code Future} is safe to use * by multiple threads concurrently. * *
Synchronization transparency
* This method and the methods of the returned {@code Future} is * synchronization transparent. * * @param the type of the result of the returned {@code Future}. Note * that no such value can actually be retrieved from the returned * {@code Future}. * @return the future representing a canceled task */ @SuppressWarnings("unchecked") public static Future canceledFuture() { // This cast is safe because the future will never return a result // therefore there is no result of which type can be observed. return (Future) CanceledFuture.INSTANCE; } /** * Invokes the {@link ExecutorService#shutdownNow() shutdownNow()} * method of all the specified executors. * * @param executors the executors to be shutted down. This argument cannot * be {@code null} and cannot contain {@code null} elements. * * @throws NullPointerException thrown if the argument is {@code null} * or any of its elements is {@code null} */ public static void shutdownExecutorsNow(ExecutorService... executors) { shutdownExecutorsNow(Arrays.asList(executors)); } /** * Invokes the {@link ExecutorService#shutdownNow() shutdownNow()} * method of all the executors in the given collection. * * @param executors the executors to be shutted down. This argument cannot * be {@code null} and cannot contain {@code null} elements. * * @throws NullPointerException thrown if the argument is {@code null} * or any of its elements is {@code null} */ public static void shutdownExecutorsNow( Collection executors) { ExceptionHelper.checkNotNullElements(executors, "executors"); for (ExecutorService executor: executors) { executor.shutdownNow(); } } /** * Waits until the specified {@code ExecutorService} terminates. That is, * this method waits until no more tasks will be executed by the given * {@code ExecutorService}. * * @param executor the executor waited to be terminated. This argument * cannot be {@code null}. * * @throws InterruptedException thrown if the current thread was interrupted * before the executor was terminated * @throws NullPointerException thrown if the specified executor is * {@code null} */ public static void awaitExecutor(ExecutorService executor) throws InterruptedException { while (!executor.isTerminated()) { executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); } } /** * Waits until all the specified {@code ExecutorService}s terminate. * That is, this method waits until no more tasks will be executed by the * specified {@code ExecutorService}s. * * @param executors the executors waited to be terminated. This argument * cannot be {@code null} and cannot contain {@code null} elements. * * @throws InterruptedException thrown if the current thread was interrupted * before at least one of the executor was terminated * @throws NullPointerException thrown if the argument is {@code null} * or any of its elements is {@code null} */ public static void awaitExecutors(ExecutorService... executors) throws InterruptedException { awaitExecutors(Arrays.asList(executors)); } /** * Waits until all the {@code ExecutorService}s in the specified collection * terminate. That is, this method waits until no more tasks will be * executed by the specified {@code ExecutorService}s. * * @param executors the executors waited to be terminated. This argument * cannot be {@code null} and cannot contain {@code null} elements. * * @throws InterruptedException thrown if the current thread was interrupted * before at least one of the executor was terminated * @throws NullPointerException thrown if the argument is {@code null} * or any of its elements is {@code null} */ public static void awaitExecutors( Collection executors) throws InterruptedException { ExceptionHelper.checkNotNullElements(executors, "executors"); for (ExecutorService executor: executors) { awaitExecutor(executor); } } /** * Waits until all the specified {@code ExecutorService}s terminate or the * given timeout elapses. That is, this method waits until no more tasks * will be executed by the specified {@code ExecutorService}s or the * specified timeout elapses. * * @param timeout the maximum time to wait in the given time unit * @param timeunit the time unit of the {@code timeout} argument. This * argument cannot be {@code null}. * @param executors the executors waited to be terminated. This argument * cannot be {@code null} and cannot contain {@code null} elements. * @return {@code true} if all the executors have terminated, {@code false} * if at least on of the executors has not yet terminated * * @throws InterruptedException thrown if the current thread was interrupted * before at least one of the executor was terminated * @throws NullPointerException thrown if the {@code timeunit} or * {@code executors} argument is {@code null} or any of the elements of * {@code executors} is {@code null} */ public static boolean awaitExecutors(long timeout, TimeUnit timeunit, ExecutorService... executors) throws InterruptedException { return awaitExecutors(timeout, timeunit, Arrays.asList(executors)); } /** * Waits until all the {@code ExecutorService}s in the specified collection * terminate or the given timeout elapses. That is, this method waits until * no more tasks will be executed by the specified {@code ExecutorService}s * or the specified timeout elapses. * * @param timeout the maximum time to wait in the given time unit * @param timeunit the time unit of the {@code timeout} argument. This * argument cannot be {@code null}. * @param executors the executors waited to be terminated. This argument * cannot be {@code null} and cannot contain {@code null} elements. * @return {@code true} if all the executors have terminated, {@code false} * if at least on of the executors has not yet terminated * * @throws InterruptedException thrown if the current thread was interrupted * before at least one of the executor was terminated * @throws NullPointerException thrown if the {@code timeunit} or * {@code executors} argument is {@code null} or any of the elements of * {@code executors} is {@code null} */ public static boolean awaitExecutors(long timeout, TimeUnit timeunit, Collection executors) throws InterruptedException { ExceptionHelper.checkNotNullElements(executors, "executors"); // Note that this code can possibly wait forever if long overflows but // that can only happen if we wait at least about 200 years. // Although it would be possible to fix this code, waiting 200 years // is nearly equivalent to waiting forever. final long toWaitNanos = timeunit.toNanos(timeout); final long startTime = System.nanoTime(); for (ExecutorService executor: executors) { long elapsedNanos = System.nanoTime() - startTime; long remainingNanos = toWaitNanos - elapsedNanos; if (remainingNanos <= 0) { break; } executor.awaitTermination(remainingNanos, TimeUnit.NANOSECONDS); } for (ExecutorService executor: executors) { if (!executor.isTerminated()) { return false; } } return true; } /** * Returns an {@code ExecutorService} forwarding all of its methods to * the given {@code ExecutorService} but the returned * {@code ExecutorService} cannot be shutted down. Attempting to shutdown * the returned {@code ExecutorService} results in an unchecked * {@code UnsupportedOperationException} to be thrown. * * @param executor the executor to which calls to be forwarded by the * returned {@code ExecutorService}. This argument cannot be {@code null}. * @return an {@code ExecutorService} which forwards all of its calls to * the specified executor but cannot be shutted down. This method never * returns {@code null}. */ public static ExecutorService asUnstoppableExecutor( ExecutorService executor) { return new UnstoppableExecutor(executor); } /** * Returns an executor executing synchronously on the calling thread without calling task recursively. * That is, if a task submitted to this executor submits a task to the same executor, the task will not be * called immediately but delayed until the top most call returns. *

* This executor is useful to prevent too deep calls potentially causing {@link StackOverflowError}. *

* For example, consider the following code: *

{@code
     * TaskExecutor executor = ExecutorsEx.syncNonRecursiveExecutor();
     * executor.execute(() -> {
     *   System.out.print("1");
     *   executor.execute(() -> System.out.print("3"));
     *   System.out.print("2");
     * });
     * }
* The above code will always print "123". *

* Note on exceptions: This implementation differs from * {@link TaskExecutors#syncNonRecursiveExecutor() TaskExecutors.syncNonRecursiveExecutor} the way it handles * exceptions happening in a task. That is, an exception happening in any of the tasks will prevent subsequently * scheduled tasks to the same thread from being executed, and the exception thrown will be propagated to * the top-most task. * * @return an executor executing synchronously on the calling thread without calling task recursively. * This method never returns {@code null}. * * @see TaskExecutors#syncNonRecursiveExecutor() */ public static Executor syncNonRecursiveExecutor() { return new SyncNonRecursiveExecutor(); } /** * Creates a new {@code ThreadPoolExecutor} which will use at most the * specified maximum thread count and daemon status. The executor will * have a default name and one second timeout before its core threads will * terminate if there are no tasks available. Note that every thread of the * executor will eventually terminate if no tasks are submitted to the * executor even if it was not shutted down (and will be restarted on * demand). * * @param maxThreadCount the maximum number of threads to be used by the * returned executor. This argument must be greater than zero. * @param isDaemon the daemon status of the threads used by the returned * executor. Note that the JVM will terminate if there are only daemon * threads are remaining. * @return the newly created {@code ThreadPoolExecutor} preinitialized * with the requested properties. This method never returns {@code null}. * * @throws IllegalArgumentException thrown if {@code maxThreadCount} is not * greater than zero * * @see #newMultiThreadedExecutor(int, long, boolean, String) */ public static ThreadPoolExecutor newMultiThreadedExecutor( int maxThreadCount, boolean isDaemon) { return newMultiThreadedExecutor(maxThreadCount, DEFAULT_THREAD_KEEPALIVE_TIME, isDaemon, null); } /** * Creates a new {@code ThreadPoolExecutor} which will use at most the * specified maximum thread count, daemon status and name. The executor will * have a one second timeout before its core threads will terminate if there * are no tasks available. Note that every thread of the executor will * eventually terminate if no tasks are submitted to the executor even if it * was not shutted down (and will be restarted on demand). * * @param maxThreadCount the maximum number of threads to be used by the * returned executor. This argument must be greater than zero. * @param isDaemon the daemon status of the threads used by the returned * executor. Note that the JVM will terminate if there are only daemon * threads are remaining. * @param poolName the name of the returned executor useful for debugging * purposes. This string will be part of the name of the threads created * by the returned executor. This argument can be {@code null} in which * case a default name will be given to this executor. * @return the newly created {@code ThreadPoolExecutor} preinitialized * with the requested properties. This method never returns {@code null}. * * @throws IllegalArgumentException thrown if {@code maxThreadCount} is not * greater than zero * * @see #newMultiThreadedExecutor(int, long, boolean, String) */ public static ThreadPoolExecutor newMultiThreadedExecutor( int maxThreadCount, boolean isDaemon, String poolName) { return newMultiThreadedExecutor(maxThreadCount, DEFAULT_THREAD_KEEPALIVE_TIME, isDaemon, poolName); } /** * Creates a new {@code ThreadPoolExecutor} which will use at most the * specified maximum thread count, daemon status, and thread keep alive * time. The executor will have a default name. Note that every thread of * the executor will eventually terminate if the specified thread keep alive * time elapses and no tasks are submitted to the executor even if it was * not shutted down (and will be restarted on demand). * * @param maxThreadCount the maximum number of threads to be used by the * returned executor. This argument must be greater than zero. * @param threadKeepAliveTime the time in milliseconds to wait after * the returned executor will shutdown idle threads. This argument * must be greater than or equal to zero. * @param isDaemon the daemon status of the threads used by the returned * executor. Note that the JVM will terminate if there are only daemon * threads are remaining. * @return the newly created {@code ThreadPoolExecutor} preinitialized * with the requested properties. This method never returns {@code null}. * * @throws IllegalArgumentException thrown if {@code maxThreadCount} is not * greater than zero or {@code threadKeepAliveTime} is a negative integer * * @see #newMultiThreadedExecutor(int, long, boolean, String) */ public static ThreadPoolExecutor newMultiThreadedExecutor( int maxThreadCount, long threadKeepAliveTime, boolean isDaemon) { return newMultiThreadedExecutor(maxThreadCount, threadKeepAliveTime, isDaemon, null); } /** * Creates a new {@code ThreadPoolExecutor} which will use at most the * specified maximum thread count, daemon status, name and thread keep alive * time. Note that every thread of the executor will * eventually terminate if the specified thread keep alive time elapses and * no tasks are submitted to the executor even if it was not shutted down * (and will be restarted on demand). * * @param maxThreadCount the maximum number of threads to be used by the * returned executor. This argument must be greater than zero. * @param threadKeepAliveTime the time in milliseconds to wait after * the returned executor will shutdown idle threads. This argument * must be greater than or equal to zero. * @param isDaemon the daemon status of the threads used by the returned * executor. Note that the JVM will terminate if there are only daemon * threads are remaining. * @param poolName the name of the returned executor useful for debugging * purposes. This string will be part of the name of the threads created * by the returned executor. This argument can be {@code null} in which * case a default name will be given to this executor. * @return the newly created {@code ThreadPoolExecutor} preinitialized * with the requested properties. This method never returns {@code null}. * * @throws IllegalArgumentException thrown if {@code maxThreadCount} is not * greater than zero or {@code threadKeepAliveTime} is a negative integer * * @see #newMultiThreadedExecutor(int, long, boolean, String) */ public static ThreadPoolExecutor newMultiThreadedExecutor( int maxThreadCount, long threadKeepAliveTime, boolean isDaemon, String poolName) { ThreadPoolExecutor result; result = new ThreadPoolExecutor(maxThreadCount, maxThreadCount, threadKeepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory(isDaemon, poolName), REJECT_POLICY); result.allowCoreThreadTimeOut(true); return result; } /** * Creates a new {@code ScheduledThreadPoolExecutor} which will use at most * the specified maximum thread count and daemon status. The executor will * have a default name and one second timeout before its core threads will * terminate if there are no tasks available. Note that every thread of the * executor will eventually terminate if no tasks are submitted to the * executor even if it was not shutted down (and will be restarted on * demand). * * @param maxThreadCount the maximum number of threads to be used by the * returned executor. This argument must be greater than zero. * @param isDaemon the daemon status of the threads used by the returned * executor. Note that the JVM will terminate if there are only daemon * threads are remaining. * @return the newly created {@code ThreadPoolExecutor} preinitialized * with the requested properties. This method never returns {@code null}. * * @throws IllegalArgumentException thrown if {@code maxThreadCount} is not * greater than zero * * @see #newMultiThreadedExecutor(int, long, boolean, String) */ public static ScheduledThreadPoolExecutor newSchedulerThreadedExecutor( int maxThreadCount, boolean isDaemon) { return newSchedulerThreadedExecutor(maxThreadCount, isDaemon, null); } /** * Creates a new {@code ScheduledThreadPoolExecutor} which will use at most * the specified maximum thread count, daemon status and name. The executor * will have a one second timeout before its core threads will terminate if * there are no tasks available. Note that every thread of the executor will * eventually terminate if no tasks are submitted to the executor even if it * was not shutted down (and will be restarted on demand). * * @param maxThreadCount the maximum number of threads to be used by the * returned executor. This argument must be greater than zero. * @param isDaemon the daemon status of the threads used by the returned * executor. Note that the JVM will terminate if there are only daemon * threads are remaining. * @param poolName the name of the returned executor useful for debugging * purposes. This string will be part of the name of the threads created * by the returned executor. This argument can be {@code null} in which * case a default name will be given to this executor. * @return the newly created {@code ThreadPoolExecutor} preinitialized * with the requested properties. This method never returns {@code null}. * * @throws IllegalArgumentException thrown if {@code maxThreadCount} is not * greater than zero * * @see #newMultiThreadedExecutor(int, long, boolean, String) */ public static ScheduledThreadPoolExecutor newSchedulerThreadedExecutor( int maxThreadCount, boolean isDaemon, String poolName) { return new ScheduledThreadPoolExecutor(maxThreadCount, new NamedThreadFactory(isDaemon, poolName), REJECT_POLICY); } private static void discardOnShutdown(Runnable task, ThreadPoolExecutor executor) { if (!executor.isShutdown()) { throw new RejectedExecutionException("Task cannot be executed."); } } /** * A {@code ThreadFactory} which creates thread with names containing a * specified string and a given daemon status and also belong to the same * thread group. Having a name for threads can be useful for debugging and * quickly identifying threads. Threads will by default have * {@code Thread.NORM_PRIORITY} as their priority. *

* This class is useful when manually creating * {@code java.util.concurrent.ThreadPoolExecutor} instances. * *

Thread safety

* Methods of this class are safe to use by multiple threads concurrently. * *

Synchronization transparency

* The methods of this class are synchronization transparent. * * @see java.util.concurrent.ThreadPoolExecutor */ public static class NamedThreadFactory implements ThreadFactory { private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); private final String namePrefix; private final boolean isDaemon; private static String getDefaultName(boolean isDaemon) { return "generic " + (isDaemon ? "daemon " : "") + "pool-" + POOL_NUMBER.getAndIncrement(); } /** * Creates a new thread factory with the specified daemon status and * a default name. * * @param isDaemon the daemon status of the threads created by this * thread factory */ public NamedThreadFactory(boolean isDaemon) { this(isDaemon, getDefaultName(isDaemon)); } /** * Creates a new thread factory with the specified daemon status and * name. The name will be included in the name of the threads created * by this thread factory. * * @param isDaemon the daemon status of the threads created by this * thread factory * @param poolName the name of this thread factory and the string to * be included in the name of the threads created by this thread * factory. This argument can be {@code null} and in this case a * default name will be used. */ public NamedThreadFactory(boolean isDaemon, String poolName) { SecurityManager s = System.getSecurityManager(); this.group = s != null ? s.getThreadGroup() : Thread.currentThread().getThreadGroup(); this.namePrefix = (poolName != null ? poolName : getDefaultName(isDaemon)) + "-thread-"; this.isDaemon = isDaemon; } /** * Creates a new thread with the properties given in the constructor. * The thread will execute the specified task. Note that the returned * thread will not be started and needed to be started manually. *

* The returned thread will be initialized to have the * {@code Thread.NORM_PRIORITY} as its priority. * * @param r the task to be executed by the returned thread. Once the * specified task returns, the returned thread will terminate. This * argument can be {@code null}, in which case the returned thread * does nothing and terminates immediately when executed. * @return the new thread with the properties given in the constructor. * This method never returns {@code null}. */ @Override public Thread newThread(Runnable r) { Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0); if (t.isDaemon() != isDaemon) { t.setDaemon(isDaemon); } if (t.getPriority() != Thread.NORM_PRIORITY) { t.setPriority(Thread.NORM_PRIORITY); } return t; } String getNamePrefix() { return namePrefix; } boolean isDaemon() { return isDaemon; } } private ExecutorsEx() { throw new AssertionError(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy