org.jboss.threads.JBossExecutors Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2017 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jboss.threads;
import java.lang.reflect.Field;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ScheduledExecutorService;
import java.util.Collection;
import java.security.PrivilegedAction;
import java.security.AccessController;
import java.security.Permission;
import org.jboss.logging.Logger;
import org.wildfly.common.Assert;
import sun.misc.Unsafe;
/**
* JBoss thread- and executor-related utility and factory methods.
*/
public final class JBossExecutors {
private static final Logger THREAD_ERROR_LOGGER = Logger.getLogger("org.jboss.threads.errors");
private JBossExecutors() {}
private static final RuntimePermission MODIFY_THREAD_PERMISSION = new RuntimePermission("modifyThread");
private static final RuntimePermission COPY_CONTEXT_CLASSLOADER_PERMISSION = new RuntimePermission("copyClassLoader");
private static final DirectExecutorService DIRECT_EXECUTOR_SERVICE = new DelegatingDirectExecutorService(SimpleDirectExecutor.INSTANCE);
private static final DirectExecutorService REJECTING_EXECUTOR_SERVICE = new DelegatingDirectExecutorService(RejectingExecutor.INSTANCE);
private static final DirectExecutorService DISCARDING_EXECUTOR_SERVICE = new DelegatingDirectExecutorService(DiscardingExecutor.INSTANCE);
@Deprecated
private static final BlockingExecutor BLOCKING_DIRECT_EXECUTOR = new DelegatingDirectBlockingExecutor(SimpleDirectExecutor.INSTANCE);
@Deprecated
private static final BlockingExecutor BLOCKING_REJECTING_EXECUTOR = new DelegatingDirectBlockingExecutor(RejectingExecutor.INSTANCE);
@Deprecated
private static final BlockingExecutor BLOCKING_DISCARDING_EXECUTOR = new DelegatingDirectBlockingExecutor(DiscardingExecutor.INSTANCE);
// ==================================================
// DIRECT EXECUTORS
// ==================================================
/**
* Get the direct executor. This executor will immediately run any task it is given, and propagate back any
* run-time exceptions thrown.
*
* @return the direct executor instance
*/
public static DirectExecutor directExecutor() {
return SimpleDirectExecutor.INSTANCE;
}
/**
* Get the direct executor service. This executor will immediately run any task it is given, and propagate back any
* run-time exceptions thrown. It cannot be shut down.
*
* @return the direct executor service instance
*/
public static DirectExecutorService directExecutorService() {
return DIRECT_EXECUTOR_SERVICE;
}
/**
* Get the rejecting executor. This executor will reject any task submitted to it.
*
* @return the rejecting executor instance
*/
public static DirectExecutor rejectingExecutor() {
return RejectingExecutor.INSTANCE;
}
/**
* Get a rejecting executor. This executor will reject any task submitted to it with the given message.
*
* @param message the reject message
* @return the rejecting executor instance
*/
public static DirectExecutor rejectingExecutor(final String message) {
return new RejectingExecutor(message);
}
/**
* Get the rejecting executor service. This executor will reject any task submitted to it. It cannot be shut down.
*
* @return the rejecting executor service instance
*/
public static DirectExecutorService rejectingExecutorService() {
return REJECTING_EXECUTOR_SERVICE;
}
/**
* Get the rejecting executor service. This executor will reject any task submitted to it with the given message.
* It cannot be shut down.
*
* @param message the reject message
* @return the rejecting executor service instance
*/
public static DirectExecutorService rejectingExecutorService(final String message) {
return protectedDirectExecutorService(rejectingExecutor(message));
}
/**
* Get the discarding executor. This executor will silently discard any task submitted to it.
*
* @return the discarding executor instance
*/
public static DirectExecutor discardingExecutor() {
return DiscardingExecutor.INSTANCE;
}
/**
* Get the discarding executor service. This executor will silently discard any task submitted to it. It cannot
* be shut down.
*
* @return the discarding executor service instance
*/
public static DirectExecutorService discardingExecutorService() {
return DISCARDING_EXECUTOR_SERVICE;
}
/**
* Create a direct executor which runs with the privileges given by the current access control context.
*
* @param delegate the executor to delegate to at the privileged level
* @return the new direct executor
*/
public static DirectExecutor privilegedExecutor(final DirectExecutor delegate) {
return new PrivilegedExecutor(delegate);
}
/**
* Create a direct executor which runs tasks with the given context class loader.
*
* @param delegate the executor to delegate to
* @param taskClassLoader the context class loader to use
* @return the new direct executor
*/
public static DirectExecutor contextClassLoaderExecutor(final DirectExecutor delegate, final ClassLoader taskClassLoader) {
return new ContextClassLoaderExecutor(taskClassLoader, delegate);
}
/**
* Create a direct executor which changes the thread name for the duration of a task.
*
* @param delegate the executor to delegate to
* @param newName the thread name to use
* @return the new direct executor
*/
public static DirectExecutor threadNameExecutor(final DirectExecutor delegate, final String newName) {
return new ThreadNameExecutor(newName, delegate);
}
/**
* Create a direct executor which changes the thread name for the duration of a task using a formatted name.
* The thread must be a {@link JBossThread}.
*
* @param delegate the executor to delegate to
* @param newName the thread name to use
* @return the new direct executor
*/
public static DirectExecutor threadFormattedNameExecutor(final DirectExecutor delegate, final String newName) {
return new ThreadFormattedNameExecutor(newName, delegate);
}
/**
* Create a direct executor which adds a note to the thread name for the duration of a task.
*
* @param delegate the executor to delegate to
* @param notation the note to use
* @return the new direct executor
*/
public static DirectExecutor threadNameNotateExecutor(final DirectExecutor delegate, final String notation) {
return new ThreadNameNotatingExecutor(notation, delegate);
}
/**
* Create a direct executor which consumes and logs errors that are thrown.
*
* @param delegate the executor to delegate to
* @param log the logger to which exceptions are written at the {@code error} level
* @return the new direct executor
*/
public static DirectExecutor exceptionLoggingExecutor(final DirectExecutor delegate, final Logger log) {
return new ExceptionLoggingExecutor(delegate, log);
}
/**
* Create a direct executor which consumes and logs errors that are thrown.
*
* @param delegate the executor to delegate to
* @param log the logger to which exceptions are written
* @param level the level at which to log exceptions
* @return the new direct executor
*/
public static DirectExecutor exceptionLoggingExecutor(final DirectExecutor delegate, final Logger log, final Logger.Level level) {
return new ExceptionLoggingExecutor(delegate, log, level);
}
/**
* Create a direct executor which consumes and logs errors that are thrown to the default thread error category
* {@code "org.jboss.threads.errors"}.
*
* @param delegate the executor to delegate to
* @return the new direct executor
*/
public static DirectExecutor exceptionLoggingExecutor(final DirectExecutor delegate) {
return exceptionLoggingExecutor(delegate, THREAD_ERROR_LOGGER);
}
/**
* Create a direct executor which delegates tasks to the given executor, and then clears all thread-local
* data after each task completes (regardless of outcome). You must have the {@link RuntimePermission}{@code ("modifyThread")}
* permission to use this method.
*
* @param delegate the delegate direct executor
* @return a resetting executor
* @throws SecurityException if the caller does not have the {@link RuntimePermission}{@code ("modifyThread")} permission
*/
public static DirectExecutor resettingExecutor(final DirectExecutor delegate) throws SecurityException {
return cleanupExecutor(delegate, threadLocalResetter());
}
/**
* Create an executor which runs the given initialization task before running its given task.
*
* @param delegate the delegate direct executor
* @param initializer the initialization task
* @return an initializing executor
*/
public static DirectExecutor initializingExecutor(final DirectExecutor delegate, final Runnable initializer) {
return new InitializingExecutor(initializer, delegate);
}
/**
* Create an executor which runs the given cleanup task after running its given task.
*
* @param delegate the delegate direct executor
* @param cleaner the cleanup task
* @return an initializing executor
*/
public static DirectExecutor cleanupExecutor(final DirectExecutor delegate, final Runnable cleaner) {
return new CleanupExecutor(cleaner, delegate);
}
// ==================================================
// DIRECT BLOCKING EXECUTORS
// ==================================================
/**
* Get an executor which executes tasks in the current thread, which implements {@code BlockingExecutor}.
*
* @return the blocking direct executor
*/
@Deprecated
public static BlockingExecutor blockingDirectExecutor() {
return BLOCKING_DIRECT_EXECUTOR;
}
/**
* Get an executor which discards all tasks, which implements {@code BlockingExecutor}.
*
* @return the executor
*/
@Deprecated
public static BlockingExecutor blockingDiscardingExecutor() {
return BLOCKING_DISCARDING_EXECUTOR;
}
/**
* Get an executor which rejects all tasks, which implements {@code BlockingExecutor}.
*
* @return the executor
*/
@Deprecated
public static BlockingExecutor blockingRejectingExecutor() {
return BLOCKING_REJECTING_EXECUTOR;
}
// ==================================================
// EXECUTORS
// ==================================================
/**
* An executor which delegates to another executor, wrapping each task in a task wrapper.
*
* @param taskWrapper the task wrapper
* @param delegate the delegate executor
* @return a wrapping executor
*/
public static Executor wrappingExecutor(final DirectExecutor taskWrapper, final Executor delegate) {
return executor(wrappingExecutor(delegate), taskWrapper);
}
/**
* An executor which delegates to the given direct executor, but implements the blocking executor interface.
* Since direct executors always execute tasks in the current thread, no blocking is possible; therefore the
* methods of BlockingExecutors always succeed or fail instantly.
*
* @param delegate the delegate direct executor
* @return the blocking executor
*/
@Deprecated
public static BlockingExecutor directBlockingExecutor(final DirectExecutor delegate) {
return new DelegatingDirectBlockingExecutor(delegate);
}
/**
* Create a wrapping executor for a delegate executor which creates an {@link #executorTask(DirectExecutor, Runnable)} for
* each task.
*
* @param delegate the delegate executor
* @return the wrapping executor
*/
public static WrappingExecutor wrappingExecutor(final Executor delegate) {
return new DelegatingWrappingExecutor(delegate);
}
/**
* An executor which delegates to a wrapping executor, wrapping each task in a task wrapper.
*
* @param delegate the delegate executor
* @param taskWrapper the task wrapper
* @return a wrapping executor
*/
public static Executor executor(final WrappingExecutor delegate, final DirectExecutor taskWrapper) {
return new DelegatingWrappedExecutor(delegate, taskWrapper);
}
/**
* Create an executor that executes each task in a new thread.
*
* @param factory the thread factory to use
* @return the executor
* @deprecated Use {@link EnhancedQueueExecutor} instead.
*/
@Deprecated
public static BlockingExecutor threadFactoryExecutor(final ThreadFactory factory) {
return new ThreadFactoryExecutor(factory, Integer.MAX_VALUE, false, directExecutor());
}
/**
* Create an executor that executes each task in a new thread. By default up to the given number of threads may run
* concurrently, after which new tasks will be rejected.
*
* @param factory the thread factory to use
* @param maxThreads the maximum number of allowed threads
* @return the executor
* @deprecated Use {@link EnhancedQueueExecutor} instead.
*/
@Deprecated
public static BlockingExecutor threadFactoryExecutor(final ThreadFactory factory, final int maxThreads) {
return new ThreadFactoryExecutor(factory, maxThreads, false, directExecutor());
}
/**
* Create an executor that executes each task in a new thread. By default up to the given number of threads may run
* concurrently, after which the caller will block or new tasks will be rejected, according to the setting of the
* {@code blocking} parameter.
*
* @param factory the thread factory to use
* @param maxThreads the maximum number of allowed threads
* @param blocking {@code true} if the submitter should block when the maximum number of threads has been reached
* @return the executor
* @deprecated Use {@link EnhancedQueueExecutor} instead.
*/
@Deprecated
public static BlockingExecutor threadFactoryExecutor(final ThreadFactory factory, final int maxThreads, final boolean blocking) {
return new ThreadFactoryExecutor(factory, maxThreads, blocking, directExecutor());
}
/**
* Create an executor that executes each task in a new thread. By default up to the given number of threads may run
* concurrently, after which the caller will block or new tasks will be rejected, according to the setting of the
* {@code blocking} parameter.
*
* @param factory the thread factory to use
* @param maxThreads the maximum number of allowed threads
* @param blocking {@code true} if the submitter should block when the maximum number of threads has been reached
* @param taskExecutor the executor which should run each task
* @return the executor
* @deprecated Use {@link EnhancedQueueExecutor} instead.
*/
@Deprecated
public static BlockingExecutor threadFactoryExecutor(final ThreadFactory factory, final int maxThreads, final boolean blocking, final DirectExecutor taskExecutor) {
return new ThreadFactoryExecutor(factory, maxThreads, blocking, taskExecutor);
}
// ==================================================
// REJECTED EXECUTION HANDLERS
// ==================================================
private static final RejectedExecutionHandler ABORT_POLICY = new ThreadPoolExecutor.AbortPolicy();
private static final RejectedExecutionHandler CALLER_RUNS_POLICY = new ThreadPoolExecutor.CallerRunsPolicy();
private static final RejectedExecutionHandler DISCARD_OLDEST_POLICY = new ThreadPoolExecutor.DiscardOldestPolicy();
private static final RejectedExecutionHandler DISCARD_POLICY = new ThreadPoolExecutor.DiscardPolicy();
/**
* Get the abort policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
*
* @return the abort policy
* @see java.util.concurrent.ThreadPoolExecutor.AbortPolicy
*/
public static RejectedExecutionHandler abortPolicy() {
return ABORT_POLICY;
}
/**
* Get the caller-runs policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
*
* @return the caller-runs policy
* @see java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy
*/
public static RejectedExecutionHandler callerRunsPolicy() {
return CALLER_RUNS_POLICY;
}
/**
* Get the discard-oldest policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
*
* @return the discard-oldest policy
* @see java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy
*/
public static RejectedExecutionHandler discardOldestPolicy() {
return DISCARD_OLDEST_POLICY;
}
/**
* Get the discard policy for a {@link java.util.concurrent.ThreadPoolExecutor}.
*
* @return the discard policy
* @see java.util.concurrent.ThreadPoolExecutor.DiscardPolicy
*/
public static RejectedExecutionHandler discardPolicy() {
return DISCARD_POLICY;
}
/**
* Get a handoff policy for a {@link java.util.concurrent.ThreadPoolExecutor}. The returned instance will
* delegate to another executor in the event that the task is rejected.
*
* @param target the target executor
* @return the new handoff policy implementation
*/
public static RejectedExecutionHandler handoffPolicy(final Executor target) {
return new HandoffRejectedExecutionHandler(target);
}
// ==================================================
// PROTECTED EXECUTOR SERVICE WRAPPERS
// ==================================================
@Deprecated
public static BlockingExecutor protectedBlockingExecutor(final BlockingExecutor target) {
return new DelegatingBlockingExecutor(target);
}
/**
* Wrap an executor with an {@code ExecutorService} instance which supports all the features of {@code ExecutorService}
* except for shutting down the executor.
*
* @param target the target executor
* @return the executor service
*/
public static ExecutorService protectedExecutorService(final Executor target) {
return new DelegatingExecutorService(target);
}
/**
* Wrap a direct executor with an {@code DirectExecutorService} instance which supports all the features of {@code ExecutorService}
* except for shutting down the executor.
*
* @param target the target executor
* @return the executor service
*/
public static DirectExecutorService protectedDirectExecutorService(final DirectExecutor target) {
return new DelegatingDirectExecutorService(target);
}
/**
* Wrap a scheduled executor with a {@code ScheduledExecutorService} instance which supports all the features of
* {@code ScheduledExecutorService} except for shutting down the executor.
*
* @param target the target executor
* @return the executor service
*/
public static ScheduledExecutorService protectedScheduledExecutorService(final ScheduledExecutorService target) {
return new DelegatingScheduledExecutorService(target);
}
/**
* Wrap a blocking executor with an {@code BlockingExecutorService} instance which supports all the features of
* {@code BlockingExecutorService} except for shutting down the executor.
*
* @param target the target executor
* @return the executor service
*/
@Deprecated
public static BlockingExecutorService protectedBlockingExecutorService(final BlockingExecutor target) {
return new DelegatingBlockingExecutorService(target);
}
// ==================================================
// THREAD FACTORIES
// ==================================================
/**
* Create a thread factory which resets all thread-local storage and delegates to the given thread factory.
* You must have the {@link RuntimePermission}{@code ("modifyThread")} permission to use this method.
*
* @param delegate the delegate thread factory
* @return the resetting thread factory
* @throws SecurityException if the caller does not have the {@link RuntimePermission}{@code ("modifyThread")}
* permission
*/
public static ThreadFactory resettingThreadFactory(final ThreadFactory delegate) throws SecurityException {
return wrappingThreadFactory(resettingExecutor(directExecutor()), delegate);
}
/**
* Creates a thread factory which executes the thread task via the given task wrapping executor.
*
* @param taskWrapper the task wrapping executor
* @param delegate the delegate thread factory
* @return the wrapping thread factory
*/
public static ThreadFactory wrappingThreadFactory(final DirectExecutor taskWrapper, final ThreadFactory delegate) {
return new WrappingThreadFactory(delegate, taskWrapper);
}
private static final Runnable TCCL_RESETTER = new Runnable() {
public void run() {
Thread.currentThread().setContextClassLoader(null);
}
public String toString() {
return "ContextClassLoader-resetting Runnable";
}
};
// ==================================================
// RUNNABLES
// ==================================================
private static final Runnable NULL_RUNNABLE = NullRunnable.getInstance();
private static final Runnable THREAD_LOCAL_RESETTER = ThreadLocalResetter.getInstance();
/**
* Get the null runnable which does nothing.
*
* @return the null runnable
*/
public static Runnable nullRunnable() {
return NULL_RUNNABLE;
}
/**
* Get a {@code Runnable} which, when executed, clears the thread-local storage of the calling thread.
* You must have the {@link RuntimePermission}{@code ("modifyThread")}
* permission to use this method.
*
* @return the runnable
* @throws SecurityException if the caller does not have the {@link RuntimePermission}{@code ("modifyThread")}
* permission
*/
public static Runnable threadLocalResetter() throws SecurityException {
checkAccess(MODIFY_THREAD_PERMISSION);
return THREAD_LOCAL_RESETTER;
}
/**
* Get a {@code Runnable} which, when executed, clears the thread context class loader (if the caller has sufficient
* privileges).
*
* @return the runnable
*/
public static Runnable contextClassLoaderResetter() {
return TCCL_RESETTER;
}
/**
* Get a task that runs the given task through the given direct executor.
*
* @param executor the executor to run the task through
* @param task the task to run
* @return an encapsulating task
*/
public static Runnable executorTask(final DirectExecutor executor, final Runnable task) {
return new ExecutorTask(executor, task);
}
/**
* Create a task that is a composite of several other tasks.
*
* @param runnables the tasks
* @return the composite task
*/
public static Runnable compositeTask(final Runnable... runnables) {
return new CompositeTask(runnables.clone());
}
/**
* Create a task that delegates to the given task, preserving the context classloader which was in effect when
* this method was invoked.
*
* @param delegate the delegate runnable
* @return the wrapping runnable
* @throws SecurityException if a security manager exists and the caller does not have the {@code "copyClassLoader"}
* {@link RuntimePermission}.
*/
public static Runnable classLoaderPreservingTask(final Runnable delegate) throws SecurityException {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(COPY_CONTEXT_CLASSLOADER_PERMISSION);
}
return classLoaderPreservingTaskUnchecked(delegate);
}
static final ClassLoader SAFE_CL;
static {
ClassLoader safeClassLoader = JBossExecutors.class.getClassLoader();
if (safeClassLoader == null) {
safeClassLoader = ClassLoader.getSystemClassLoader();
}
if (safeClassLoader == null) {
safeClassLoader = new ClassLoader() {
};
}
SAFE_CL = safeClassLoader;
}
static Runnable classLoaderPreservingTaskUnchecked(final Runnable delegate) {
Assert.checkNotNullParam("delegate", delegate);
return new ContextClassLoaderSavingRunnable(getContextClassLoader(Thread.currentThread()), delegate);
}
static final Unsafe unsafe;
static final long contextClassLoaderOffs;
static {
unsafe = AccessController.doPrivileged(new PrivilegedAction() {
public Unsafe run() {
try {
final Field field = Unsafe.class.getDeclaredField("theUnsafe");
field.setAccessible(true);
return (Unsafe) field.get(null);
} catch (IllegalAccessException e) {
throw new IllegalAccessError(e.getMessage());
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
});
try {
contextClassLoaderOffs = unsafe.objectFieldOffset(Thread.class.getDeclaredField("contextClassLoader"));
} catch (NoSuchFieldException e) {
throw new NoSuchFieldError(e.getMessage());
}
}
/**
* Privileged method to get the context class loader of the given thread.
*
* @param thread the thread to introspect
* @return the context class loader
*/
static ClassLoader getContextClassLoader(final Thread thread) {
return (ClassLoader) unsafe.getObject(thread, contextClassLoaderOffs);
}
/**
* Privileged method to get and set the context class loader of the given thread.
*
* @param thread the thread to introspect
* @param newClassLoader the new context class loader
* @return the old context class loader
*/
static ClassLoader getAndSetContextClassLoader(final Thread thread, final ClassLoader newClassLoader) {
try {
return getContextClassLoader(thread);
} finally {
setContextClassLoader(thread, newClassLoader);
}
}
/**
* Privileged method to set the context class loader of the given thread.
*
* @param thread the thread to introspect
* @param classLoader the new context class loader
*/
static void setContextClassLoader(final Thread thread, final ClassLoader classLoader) {
unsafe.putObject(thread, contextClassLoaderOffs, classLoader);
}
/**
* Privileged method to clear the context class loader of the given thread to a safe non-{@code null} value.
*
* @param thread the thread to introspect
*/
static void clearContextClassLoader(final Thread thread) {
unsafe.putObject(thread, contextClassLoaderOffs, SAFE_CL);
}
/**
* Create a task that is a composite of several other tasks.
*
* @param runnables the tasks
* @return the composite task
*/
public static Runnable compositeTask(final Collection runnables) {
return new CompositeTask(runnables.toArray(new Runnable[runnables.size()]));
}
static void checkAccess(Permission permission) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(permission);
}
}
// ==================================================
// UNCAUGHT EXCEPTION HANDLERS
// ==================================================
/**
* Get an uncaught exception handler which logs to the given logger.
*
* @param log the logger
* @return the handler
*/
public static Thread.UncaughtExceptionHandler loggingExceptionHandler(final Logger log) {
return new LoggingUncaughtExceptionHandler(log);
}
/**
* Get an uncaught exception handler which logs to the given logger.
*
* @param categoryName the name of the logger category to log to
* @return the handler
*/
public static Thread.UncaughtExceptionHandler loggingExceptionHandler(final String categoryName) {
return new LoggingUncaughtExceptionHandler(Logger.getLogger(categoryName));
}
private static final Thread.UncaughtExceptionHandler LOGGING_HANDLER = loggingExceptionHandler(THREAD_ERROR_LOGGER);
/**
* Get an uncaught exception handler which logs to the default error logger.
*
* @return the handler
*/
public static Thread.UncaughtExceptionHandler loggingExceptionHandler() {
return LOGGING_HANDLER;
}
private static void logError(final R runnable, final Throwable t, final String method) {
THREAD_ERROR_LOGGER.errorf(t, "Notifier %s() method invocation failed for task %s", method, runnable);
}
private static void started(TaskNotifier super R, ? super A> notifier, R runnable, A attachment) {
try {
notifier.started(runnable, attachment);
} catch (Throwable t) {
logError(runnable, t, "started");
}
}
private static void finished(TaskNotifier super R, ? super A> notifier, R runnable, A attachment) {
try {
notifier.finished(runnable, attachment);
} catch (Throwable t) {
logError(runnable, t, "finished");
}
}
private static void failed(TaskNotifier super R, ? super A> notifier, Throwable reason, R runnable, A attachment) {
try {
notifier.failed(runnable, reason, attachment);
} catch (Throwable t) {
logError(runnable, t, "failed");
}
}
/**
* Run a task through the given direct executor, invoking the given notifier with the given attachment.
*
* @param task the task
* @param directExecutor the executor
* @param notifier the notifier
* @param attachment the attachment
* @param the task type
* @param the attachment type
*/
public static void run(R task, DirectExecutor directExecutor, TaskNotifier super R, ? super A> notifier, A attachment) {
started(notifier, task, attachment);
boolean ok = false;
try {
directExecutor.execute(task);
ok = true;
} catch (RuntimeException t) {
failed(notifier, t, task, attachment);
throw t;
} catch (Error t) {
failed(notifier, t, task, attachment);
throw t;
} catch (Throwable t) {
failed(notifier, t, task, attachment);
throw Messages.msg.unknownThrowable(t);
} finally {
if (ok) finished(notifier, task, attachment);
}
}
/**
* Run a task, invoking the given notifier with the given attachment.
*
* @param task the task
* @param notifier the notifier
* @param attachment the attachment
* @param the task type
* @param the attachment type
*/
public static void run(R task, TaskNotifier super R, ? super A> notifier, A attachment) {
run(task, directExecutor(), notifier, attachment);
}
/**
* Get a notifying runnable wrapper for a task. The notifier will be invoked when the task is run.
*
* @param task the task
* @param notifier the notifier
* @param attachment the attachment
* @param the task type
* @param the attachment type
* @return the wrapping runnable
*/
public static Runnable notifyingRunnable(R task, TaskNotifier super R, ? super A> notifier, A attachment) {
return new NotifyingRunnable(task, notifier, attachment);
}
/**
* Get a notifying direct executor. The notifier will be invoked when each task is run.
*
* @param delegate the executor which will actually run the task
* @param notifier the notifier
* @param attachment the attachment
* @param the attachment type
* @return the direct executor
*/
public static DirectExecutor notifyingDirectExecutor(DirectExecutor delegate, TaskNotifier notifier, A attachment) {
return new NotifyingDirectExecutor(delegate, notifier, attachment);
}
/**
* Execute a task uninterruptibly.
*
* @param executor the executor to delegate to
* @param task the task to execute
* @throws RejectedExecutionException if the task was rejected by the executor
*/
public static void executeUninterruptibly(Executor executor, Runnable task) throws RejectedExecutionException {
boolean intr = Thread.interrupted();
try {
for (;;) {
try {
executor.execute(task);
return;
} catch (ExecutionInterruptedException e) {
intr |= Thread.interrupted();
}
}
} finally {
if (intr) {
Thread.currentThread().interrupt();
}
}
}
/**
* Get an executor which executes tasks uninterruptibly in the event of blocking.
*
* @param delegate the delegate executor
* @return the uninterruptible executor
*/
public static Executor uninterruptibleExecutor(final Executor delegate) {
if (delegate instanceof UninterruptibleExecutor) {
return delegate;
} else {
return new UninterruptibleExecutor(delegate);
}
}
/**
* Create a builder for a dependent task.
*
* @param executor the executor to use
* @param task the task to run when all dependencies are met
* @return the builder
*/
public static DependencyTaskBuilder dependencyTaskBuilder(final Executor executor, final Runnable task) {
return new DependencyTaskBuilder(executor, task);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy