ttl-core/src/main/java/com/alibaba/ttl3/executor/TtlExecutors.java
package com.alibaba.ttl3.executor;
import com.alibaba.ttl3.TransmittableThreadLocal;
import com.alibaba.ttl3.agent.TtlAgentStatus;
import com.alibaba.ttl3.spi.TtlEnhanced;
import com.alibaba.ttl3.spi.TtlWrapper;
import edu.umd.cs.findbugs.annotations.NonNull;
import edu.umd.cs.findbugs.annotations.Nullable;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import org.jetbrains.annotations.Contract;
import java.util.Comparator;
import java.util.concurrent.*;
import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;
/**
* Util methods for TTL wrapper of jdk executors.
*
* <ol>
* <li>wrap/check/unwrap methods for TTL wrapper of
* jdk executors({@link Executor}, {@link ExecutorService}, {@link ScheduledExecutorService}).</li>
* <li>wrap/check/unwrap methods for disable Inheritable wrapper of {@link ThreadFactory}.</li>
* <li>wrap/check/unwrap methods for disable Inheritable wrapper of {@link ForkJoinWorkerThreadFactory}.</li>
* <li>wrap/check/unwrap methods for {@code TtlRunnableUnwrapComparator} wrapper of {@link PriorityBlockingQueue}
* for {@link ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue)}.</li>
* </ol>
* <p>
* <b><i>Note:</i></b>
* <ul>
* <li>all method is {@code null}-safe.
* for wrap/unwrap methods when input parameter is {@code null}, return {@code null}.
* for check methods when input parameter is {@code null}, return {@code false}.</li>
* <li>skip wrap/decoration thread pool/{@code executor}(aka. just return input {@code executor})
* when ttl agent is loaded, Or when input {@code executor} is already wrapped/decorated.</li>
* </ul>
*
* @author Jerry Lee (oldratlee at gmail dot com)
* @see Executor
* @see ExecutorService
* @see ScheduledExecutorService
* @see ThreadPoolExecutor
* @see ScheduledThreadPoolExecutor
* @see Executors
* @see ThreadFactory
* @see Executors#defaultThreadFactory()
* @see ForkJoinPool
* @see ForkJoinWorkerThreadFactory
* @see ForkJoinPool#defaultForkJoinWorkerThreadFactory
* @see ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue)
* @see PriorityBlockingQueue
*/
public final class TtlExecutors {
///////////////////////////////////////////////////////////////////////////
// Executor utils
///////////////////////////////////////////////////////////////////////////
/**
* {@link TransmittableThreadLocal} Wrapper of {@link Executor},
* transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable}
* to the execution time of {@link Runnable}.
*
* @param executor input Executor
* @return wrapped Executor
* @see com.alibaba.ttl3.TtlRunnable#get(Runnable, boolean, boolean)
* @see com.alibaba.ttl3.TtlCallable#get(Callable, boolean, boolean)
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
public static Executor getTtlExecutor(@Nullable Executor executor) {
if (TtlAgentStatus.getInstance().isTtlAgentLoaded() || executor == null || executor instanceof TtlEnhanced) {
return executor;
}
return new ExecutorTtlWrapper(executor, true);
}
/**
* {@link TransmittableThreadLocal} Wrapper of {@link ExecutorService},
* transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable}
* to the execution time of {@link Runnable} or {@link Callable}.
*
* @param executorService input ExecutorService
* @return wrapped ExecutorService
* @see com.alibaba.ttl3.TtlRunnable#get(Runnable, boolean, boolean)
* @see com.alibaba.ttl3.TtlCallable#get(Callable, boolean, boolean)
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
public static ExecutorService getTtlExecutorService(@Nullable ExecutorService executorService) {
if (TtlAgentStatus.getInstance().isTtlAgentLoaded() || executorService == null || executorService instanceof TtlEnhanced) {
return executorService;
}
return new ExecutorServiceTtlWrapper(executorService, true);
}
/**
* {@link TransmittableThreadLocal} Wrapper of {@link ScheduledExecutorService},
* transmit the {@link TransmittableThreadLocal} from the task submit time of {@link Runnable} or {@link Callable}
* to the execution time of {@link Runnable} or {@link Callable}.
*
* @param scheduledExecutorService input scheduledExecutorService
* @return wrapped scheduledExecutorService
* @see com.alibaba.ttl3.TtlRunnable#get(Runnable, boolean, boolean)
* @see com.alibaba.ttl3.TtlCallable#get(Callable, boolean, boolean)
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
public static ScheduledExecutorService getTtlScheduledExecutorService(@Nullable ScheduledExecutorService scheduledExecutorService) {
if (TtlAgentStatus.getInstance().isTtlAgentLoaded() || scheduledExecutorService == null || scheduledExecutorService instanceof TtlEnhanced) {
return scheduledExecutorService;
}
return new ScheduledExecutorServiceTtlWrapper(scheduledExecutorService, true);
}
/**
* check the executor is a TTL executor wrapper or not.
* <p>
* if the parameter executor is TTL wrapper, return {@code true}, otherwise {@code false}.
* <p>
* NOTE: if input executor is {@code null}, return {@code false}.
*
* @param executor input executor
* @param <T> Executor type
* @see #getTtlExecutor(Executor)
* @see #getTtlExecutorService(ExecutorService)
* @see #getTtlScheduledExecutorService(ScheduledExecutorService)
* @see #unwrapTtlExecutor(Executor)
*/
public static <T extends Executor> boolean isTtlExecutor(@Nullable T executor) {
return executor instanceof TtlWrapper;
}
/**
* Unwrap TTL executor wrapper to the original/underneath one.
* <p>
* if the parameter executor is TTL wrapper, return the original/underneath executor;
* otherwise, just return the input parameter executor.
* <p>
* NOTE: if input executor is {@code null}, return {@code null}.
*
* @param executor input executor
* @param <T> Executor type
* @see #getTtlExecutor(Executor)
* @see #getTtlExecutorService(ExecutorService)
* @see #getTtlScheduledExecutorService(ScheduledExecutorService)
* @see #isTtlExecutor(Executor)
* @see com.alibaba.ttl3.TtlWrappers#unwrap(Object)
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
@SuppressWarnings("unchecked")
public static <T extends Executor> T unwrapTtlExecutor(@Nullable T executor) {
if (!isTtlExecutor(executor)) return executor;
return (T) ((ExecutorTtlWrapper) executor).unwrap();
}
/**
* Wrapper of {@link ThreadFactory}, disable inheritable.
*
* @param threadFactory input thread factory
* @see TtlExecutors#getDisableInheritableForkJoinWorkerThreadFactory
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
public static ThreadFactory getDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {
if (threadFactory == null || isDisableInheritableThreadFactory(threadFactory)) return threadFactory;
return new DisableInheritableThreadFactoryWrapper(threadFactory);
}
/**
* Wrapper of {@link Executors#defaultThreadFactory()}, disable inheritable.
*
* @see #getDisableInheritableThreadFactory(ThreadFactory)
* @see TtlExecutors#getDefaultDisableInheritableForkJoinWorkerThreadFactory()
*/
@NonNull
public static ThreadFactory getDefaultDisableInheritableThreadFactory() {
return getDisableInheritableThreadFactory(Executors.defaultThreadFactory());
}
/**
* check the {@link ThreadFactory} is {@code DisableInheritableThreadFactory} or not.
*
* @see TtlExecutors#getDisableInheritableForkJoinWorkerThreadFactory
* @see #getDefaultDisableInheritableThreadFactory()
*/
public static boolean isDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {
return threadFactory instanceof DisableInheritableThreadFactoryWrapper;
}
/**
* Unwrap {@code DisableInheritableThreadFactory} to the original/underneath one.
*
* @see #getDisableInheritableThreadFactory(ThreadFactory)
* @see #getDefaultDisableInheritableThreadFactory()
* @see #isDisableInheritableThreadFactory(ThreadFactory)
* @see TtlExecutors#unwrapDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)
* @see com.alibaba.ttl3.TtlWrappers#unwrap(Object)
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
public static ThreadFactory unwrapDisableInheritableThreadFactory(@Nullable ThreadFactory threadFactory) {
if (!isDisableInheritableThreadFactory(threadFactory)) return threadFactory;
return ((DisableInheritableThreadFactoryWrapper) threadFactory).unwrap();
}
///////////////////////////////////////////////////////////////////////////
// ForkJoinPool utils
///////////////////////////////////////////////////////////////////////////
/**
* Wrapper of {@link ForkJoinWorkerThreadFactory}, disable inheritable.
*
* @param threadFactory input thread factory
* @see TtlExecutors#getDisableInheritableThreadFactory(ThreadFactory)
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
public static ForkJoinWorkerThreadFactory getDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) {
if (threadFactory == null || isDisableInheritableForkJoinWorkerThreadFactory(threadFactory))
return threadFactory;
return new DisableInheritableForkJoinWorkerThreadFactoryWrapper(threadFactory);
}
/**
* Wrapper of {@link ForkJoinPool#defaultForkJoinWorkerThreadFactory}, disable inheritable.
*
* @see #getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)
* @see TtlExecutors#getDefaultDisableInheritableThreadFactory()
*/
@NonNull
public static ForkJoinWorkerThreadFactory getDefaultDisableInheritableForkJoinWorkerThreadFactory() {
return getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinPool.defaultForkJoinWorkerThreadFactory);
}
/**
* check the {@link ForkJoinWorkerThreadFactory} is {@code DisableInheritableForkJoinWorkerThreadFactory} or not.
*
* @see #getDisableInheritableForkJoinWorkerThreadFactory(ForkJoinWorkerThreadFactory)
* @see #getDefaultDisableInheritableForkJoinWorkerThreadFactory()
*/
public static boolean isDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) {
return threadFactory instanceof DisableInheritableForkJoinWorkerThreadFactoryWrapper;
}
/**
* Unwrap {@code DisableInheritableForkJoinWorkerThreadFactory} to the original/underneath one.
*
* @see com.alibaba.ttl3.TtlWrappers#unwrap(Object)
* @see TtlExecutors#unwrapDisableInheritableThreadFactory(ThreadFactory)
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
public static ForkJoinWorkerThreadFactory unwrapDisableInheritableForkJoinWorkerThreadFactory(@Nullable ForkJoinWorkerThreadFactory threadFactory) {
if (!isDisableInheritableForkJoinWorkerThreadFactory(threadFactory)) return threadFactory;
return ((DisableInheritableForkJoinWorkerThreadFactoryWrapper) threadFactory).unwrap();
}
///////////////////////////////////////////////////////////////////////////
// Comparator utils
///////////////////////////////////////////////////////////////////////////
/**
* Wrapper of {@code Comparator<Runnable>} which unwrap {@link com.alibaba.ttl3.TtlRunnable} before compare,
* aka {@code TtlRunnableUnwrapComparator}.
* <p>
* Prepared for {@code comparator} parameter of constructor
* {@link PriorityBlockingQueue#PriorityBlockingQueue(int, Comparator)}.
* <p>
* {@link PriorityBlockingQueue} can be used by constructor
* {@link ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue)}.
*
* @param comparator input comparator
* @return wrapped comparator
* @see ThreadPoolExecutor
* @see ThreadPoolExecutor#ThreadPoolExecutor(int, int, long, TimeUnit, BlockingQueue)
* @see PriorityBlockingQueue
* @see PriorityBlockingQueue#PriorityBlockingQueue(int, Comparator)
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
public static Comparator<Runnable> getTtlRunnableUnwrapComparator(@Nullable Comparator<Runnable> comparator) {
if (comparator == null || isTtlRunnableUnwrapComparator(comparator)) return comparator;
return new TtlUnwrapComparator<>(comparator);
}
@SuppressWarnings({"unchecked", "rawtypes"})
private static final Comparator INSTANCE = new TtlUnwrapComparator(ComparableComparator.INSTANCE);
/**
* {@code TtlRunnableUnwrapComparator} that compares {@link Comparable Comparable} objects.
*
* @see #getTtlRunnableUnwrapComparator(Comparator)
*/
@NonNull
@SuppressWarnings("unchecked")
public static Comparator<Runnable> getTtlRunnableUnwrapComparatorForComparableRunnable() {
return (Comparator<Runnable>) INSTANCE;
}
/**
* check the {@code Comparator<Runnable>} is a wrapper {@code TtlRunnableUnwrapComparator} or not.
*
* @see #getTtlRunnableUnwrapComparator(Comparator)
* @see #getTtlRunnableUnwrapComparatorForComparableRunnable()
*/
public static boolean isTtlRunnableUnwrapComparator(@Nullable Comparator<Runnable> comparator) {
return comparator instanceof TtlUnwrapComparator;
}
/**
* Unwrap {@code TtlRunnableUnwrapComparator} to the original/underneath {@code Comparator<Runnable>}.
*
* @see #getTtlRunnableUnwrapComparator(Comparator)
* @see #getTtlRunnableUnwrapComparatorForComparableRunnable()
* @see #isTtlRunnableUnwrapComparator(Comparator)
* @see com.alibaba.ttl3.TtlWrappers#unwrap(Object)
*/
@Nullable
@Contract(value = "null -> null; !null -> !null", pure = true)
public static Comparator<Runnable> unwrapTtlRunnableUnwrapComparator(@Nullable Comparator<Runnable> comparator) {
if (!isTtlRunnableUnwrapComparator(comparator)) return comparator;
return ((TtlUnwrapComparator<Runnable>) comparator).unwrap();
}
@SuppressFBWarnings("CT_CONSTRUCTOR_THROW")
private TtlExecutors() {
throw new InstantiationError("Must not instantiate this class");
}
}