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

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

package org.jtrim2.executor;

import java.util.Objects;
import org.jtrim2.cancel.CancellationToken;

/**
 * Contains static helper and factory methods for various useful
 * {@link TaskExecutor} and {@link TaskExecutorService} implementations.
 * 

* 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 TaskExecutors { /** * Returns an {@code TaskExecutorService} forwarding all of its methods to * the given {@code TaskExecutorService} but the returned * {@code TaskExecutorService} 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 TaskExecutorService}. This argument cannot be * {@code null}. * @return an {@code TaskExecutorService} which forwards all of its calls to * the specified executor but cannot be shutted down. This method never * returns {@code null}. * * @throws NullPointerException thrown if the specified executor is * {@code null} */ public static TaskExecutorService asUnstoppableExecutor( TaskExecutorService executor) { if (executor instanceof UnstoppableTaskExecutor) { return executor; } else { return new UnstoppableTaskExecutor(executor); } } /** * Returns an executor which forwards task to a given executor and executes * tasks without running them concurrently. The tasks will be executed in * the order the they were submitted to the * {@link TaskExecutor#execute(CancellationToken, CancelableTask) execute} * method of the returned {@code TaskExecutor}. Subsequent tasks, attempted to * be executed while another one scheduled to this executor is running will * be queued and be executed when the running task terminates. Note that * even if a tasks schedules a task to this executor, the scheduled task * will only be called after the scheduling task terminates. See the * following code for clarification: *
{@code
     * void doPrint(TaskExecutor executor) {
     *   TaskExecutor inOrderExec = TaskExecutors.inOrderExecutor(executor);
     *   executor.execute(() -> {
     *     System.out.print("1");
     *     executor.execute(() -> System.out.print("3"));
     *     System.out.print("2");
     *   });
     * }
     * }
* The {@code doPrint} method will always print "123", regardless what the * passed executor is. *

* The returned executor is useful for calling tasks which are not safe to * be called concurrently. This executor will effectively serialize the * calls as if all the tasks were executed by a single thread even if the * underlying executor uses multiple threads to execute tasks. *

* Note that this implementation does not expect the tasks to be * synchronization transparent but of course, they cannot wait for * each other. If a tasks executed by this executor submits a task to this * same executor and waits for this newly submitted tasks, it will dead-lock * always. This is because no other tasks may run concurrently with the * already running tasks and therefore the newly submitted task has no * chance to start. *

* Note: This method may return the same executor passed in the * argument if the specified executor already executes tasks in the order they * were submitted. * Warning: Instances of this class use an internal queue for tasks * yet to be executed and if tasks are submitted to executor faster than it * can actually execute it will eventually cause the internal buffer to * overflow and throw an {@link OutOfMemoryError}. This can occur even if * the underlying executor does not execute tasks scheduled to them because * tasks will be queued immediately by the {@code execute} method before * actually executing the task. * * @param executor the executor to which tasks will be eventually forwarded * to. This argument cannot be {@code null}. * @return executor which forwards task to a given executor and executes * tasks without running them concurrently. This method never returns * {@code null} and may return the same executor passed in the argument if * the specified executor executes tasks in the order they were submitted. * * @throws NullPointerException thrown if the specified executor is * {@code null} * * @see SingleThreadedExecutor * @see #inOrderSimpleExecutor(TaskExecutor) */ public static MonitorableTaskExecutor inOrderExecutor(TaskExecutor executor) { Objects.requireNonNull(executor, "executor"); if (FifoExecutor.isFifoExecutor(executor) && executor instanceof MonitorableTaskExecutor) { return (MonitorableTaskExecutor) executor; } else { return new InOrderTaskExecutor(executor); } } /** * Returns an executor which forwards task to a given executor and executes * tasks without running them concurrently (this method differs from * {@link #inOrderExecutor(TaskExecutor)} only by not necessarily returning * a {@link MonitorableTaskExecutor}). The tasks will be executed in the * order the they were submitted to the * {@link TaskExecutor#execute(CancellationToken, CancelableTask) execute} * method of the returned {@code TaskExecutor}. Subsequent tasks, attempted to * be executed while another one scheduled to this executor is running will * be queued and be executed when the running task terminates. Note that * even if a tasks schedules a task to this executor, the scheduled task * will only be called after the scheduling task terminates. See the * following code for clarification: *

{@code
     * void doPrint(TaskExecutor executor) {
     *   TaskExecutor inOrderExec = TaskExecutors.inOrderSimpleExecutor(executor);
     *   executor.execute(() -> {
     *     System.out.print("1");
     *     executor.execute(() -> System.out.print("3"));
     *     System.out.print("2");
     *   });
     * }
     * }
* The {@code doPrint} method will always print "123", regardless what the * passed executor is. *

* The returned executor is useful for calling tasks which are not safe to * be called concurrently. This executor will effectively serialize the * calls as if all the tasks were executed by a single thread even if the * underlying executor uses multiple threads to execute tasks. *

* Note that this implementation does not expect the tasks to be * synchronization transparent but of course, they cannot wait for * each other. If a tasks executed by this executor submits a task to this * same executor and waits for this newly submitted tasks, it will dead-lock * always. This is because no other tasks may run concurrently with the * already running tasks and therefore the newly submitted task has no * chance to start. *

* Note: This method may return the same executor passed in the * argument if the specified executor already executes tasks in submittation * order. * Warning: Instances of this class use an internal queue for tasks * yet to be executed and if tasks are submitted to executor faster than it * can actually execute it will eventually cause the internal buffer to * overflow and throw an {@link OutOfMemoryError}. This can occur even if * the underlying executor does not execute tasks scheduled to them because * tasks will be queued immediately by the {@code execute} method before * actually executing the task. * * @param executor the executor to which tasks will be eventually forwarded * to. This argument cannot be {@code null}. * @return executor which forwards task to a given executor and executes * tasks without running them concurrently. This method never returns * {@code null} and may return the same executor passed in the argument if * the specified executor executes tasks in submittation order. * * @throws NullPointerException thrown if the specified executor is * {@code null} * * @see SingleThreadedExecutor * @see #inOrderExecutor(TaskExecutor) */ public static TaskExecutor inOrderSimpleExecutor(TaskExecutor executor) { Objects.requireNonNull(executor, "executor"); if (FifoExecutor.isFifoExecutor(executor)) { return executor; } else { return new InOrderTaskExecutor(executor); } } /** * Returns an executor which invokes tasks in the order they were scheduled * to it. The tasks will execute in one of the * {@link TaskExecutor#execute(CancellationToken, CancelableTask) execute} * calls of the same executor but the user has no influence in which one it * will actually be called. *

* This method is effectively equivalent to calling * {@code inOrderExecutor(SyncTaskExecutor.getSimpleExecutor())}. * * @return an executor which invokes tasks in the order they were scheduled * to it. This method never returns {@code null}. */ public static MonitorableTaskExecutor inOrderSyncExecutor() { return inOrderExecutor(SyncTaskExecutor.getSimpleExecutor()); } /** * Returns a {@code TaskExecutorService} which upgrades the specified * {@link TaskExecutor TaskExecutor} to provide all the features of a * {@code TaskExecutorService}. Tasks submitted to the returned * {@code TaskExecutorService} will be forwarded to the {@code execute} * method of the specified {@code TaskExecutor}. *

* Shutting down the returned executor will shutdown the returned executor * but not the passed {@code TaskExecutor} even if it implemented the * {@code TaskExecutorService} interface. *

* Note: If you don't want to shutdown the return * {@code TaskExecutorService}, you should rather use the * {@link #upgradeToUnstoppable(TaskExecutor) upgradeToUnstoppable} method. * * @param executor the {@code TaskExecutor} to which the returned * {@code TaskExecutorService} will forward submitted tasks to be * executed. This argument cannot be {@code null}. * @return a {@code TaskExecutorService} which upgrades the specified * {@link TaskExecutor TaskExecutor} to provide all the features of a * {@code TaskExecutorService}. This method never returns {@code null}. * * @throws NullPointerException thrown if the specified {@code TaskExecutor} * is {@code null} * * @see #upgradeToUnstoppable(TaskExecutor) */ public static TaskExecutorService upgradeToStoppable(TaskExecutor executor) { return new UpgradedTaskExecutor(executor); } /** * Returns a {@code TaskExecutorService} which upgrades the specified * {@link TaskExecutor TaskExecutor} to provide all the features of a * {@code TaskExecutorService} except that the returned executer cannot be * shut down. Tasks submitted to the returned {@code TaskExecutorService} * will be forwarded to the {@code execute} method of the specified * {@code TaskExecutor}. *

* The returned executor cannot be shut down. Attempting to do so will cause * an unchecked {@code UnsupportedOperationException} to be thrown. * * @param executor the {@code TaskExecutor} to which the returned * {@code TaskExecutorService} will forward submitted tasks to be * executed. This argument cannot be {@code null}. * @return a {@code TaskExecutorService} which upgrades the specified * {@link TaskExecutor TaskExecutor} to provide all the features of a * {@code TaskExecutorService}. This method never returns {@code null}. * * @throws NullPointerException thrown if the specified {@code TaskExecutor} * is {@code null} * * @see #upgradeToStoppable(TaskExecutor) */ public static TaskExecutorService upgradeToUnstoppable(TaskExecutor executor) { if (executor instanceof UnstoppableTaskExecutor) { return (TaskExecutorService) executor; } else { return new UnstoppableTaskExecutor(new UpgradedTaskExecutor(executor)); } } /** * Returns an executor which submits tasks to the specified executor and * is context aware. *

* Note that, tasks passed to the executor specified in the parameters has * no effect on the returned executor. * * @param executor the specified executor to which the returned executor * will submit tasks to. This argument cannot be {@code null}. * @return an executor which submits tasks to the specified executor and * is context aware. This method never returns {@code null}. * * @throws NullPointerException thrown if the specified executor is * {@code null} */ public static ContextAwareWrapper contextAware(TaskExecutor executor) { return new ContextAwareWrapper(executor); } /** * Returns an executor which submits tasks to the specified executor and * is context aware. If the passed executor is already an instance of * {@link ContextAwareTaskExecutor} then the passed executor is returned. *

* Note that, tasks passed to the executor specified in the parameters may * or may not be count as running in the context of the returned executor. * * @param executor the specified executor to which the returned executor * will submit tasks to. This argument cannot be {@code null}. * @return an executor which submits tasks to the specified executor and * is context aware. This method never returns {@code null}. * * @throws NullPointerException thrown if the specified executor is * {@code null} */ public static ContextAwareTaskExecutor contextAwareIfNecessary(TaskExecutor executor) { if (executor instanceof ContextAwareTaskExecutor) { return (ContextAwareTaskExecutor) executor; } else { return contextAware(executor); } } /** * Returns a {@code TaskExecutorService} which forwards tasks to the * specified {@code TaskExecutorService} but always logs exceptions thrown * by tasks sheduled to the returned executor. This is useful when debugging * because a {@code TaskExecutorService} implementation cannot determine if * an exception thrown by a task expected by the client code or not. *

* Other than logging exceptions the returned executor delegates all method * calls to the appropriate method of the specified executor. *

* The exceptions are logged in a {@code SEVERE} level logmessage. *

* Warning: The returned executor will not log exceptions thrown by * cleanup tasks because {@code TaskExecutorService} implementations are * expected to log or rethrow them. * * @param executor the {@code TaskExecutorService} to which method calls are * forwarded to. This argument cannot be {@code null}. * @return a {@code TaskExecutorService} which forwards tasks to the * specified {@code TaskExecutorService} but always logs exceptions thrown * by tasks sheduled to the returned executor. This method never returns * {@code null}. * * @throws NullPointerException thrown if the specified executor is * {@code null} */ public static TaskExecutorService debugExecutorService(TaskExecutorService executor) { return new DebugTaskExecutorService(executor); } /** * Returns a {@code TaskExecutor} which forwards tasks to the specified * {@code TaskExecutor} but always logs exceptions thrown by tasks sheduled * to the returned executor. This is useful when debugging because a * {@code TaskExecutor} implementation cannot determine if an exception * thrown by a task expected by the client code or not. *

* Other than logging exceptions the returned executor delegates all method * calls to the appropriate method of the specified executor. *

* The exceptions are logged in a {@code SEVERE} level logmessage. * * @param executor the {@code TaskExecutor} to which method calls are * forwarded to. This argument cannot be {@code null}. * @return a {@code TaskExecutor} which forwards tasks to the specified * {@code TaskExecutor} but always logs exceptions thrown by tasks * scheduled to the returned executor. This method never returns * {@code null}. * * @throws NullPointerException thrown if the specified executor is * {@code null} */ public static TaskExecutor debugExecutor(TaskExecutor executor) { return new DebugTaskExecutor(executor); } private TaskExecutors() { throw new AssertionError(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy