+ * Note:
+ * {@link TransmittableThreadLocal} extends {@link InheritableThreadLocal},
+ * so {@link TransmittableThreadLocal} first is a {@link InheritableThreadLocal}.
+ * If the inheritable ability from {@link InheritableThreadLocal} has potential leaking problem,
+ * you can disable the inheritable ability:
+ *
+ * ❶ by wrapping thread factory using method
+ * {@link TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)} /
+ * {@link TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory()}
+ * for thread pooling components({@link java.util.concurrent.ThreadPoolExecutor}, {@link java.util.concurrent.ForkJoinPool}).
+ * Inheritable feature in thread pooling components should never happen,
+ * because threads in thread pooling components is pre-created and pooled, these threads is neutral for biz logic/data.
+ *
+ * You can turn on "disable inheritable for thread pool" by {@link TtlAgent}
+ * so as to wrap thread factory for thread pooling components ({@link java.util.concurrent.ThreadPoolExecutor},
+ * {@link java.util.concurrent.ForkJoinPool}) automatically and transparently.
+ *
+ * ❷ or by overriding method {@link #childValue(Object)}. + * Whether the value should be inheritable or not can be controlled by the data owner, + * disable it carefully when data owner have a clear idea. + *
{@code TransmittableThreadLocal+ *transmittableThreadLocal = new TransmittableThreadLocal () { + * protected String childValue(String parentValue) { + * return initialValue(); + * } + * }}
+ * More discussion about "disable the inheritable ability"
+ * see
+ * issue #100: disable Inheritable when it's not necessary and buggy.
+ *
+ * @author Jerry Lee (oldratlee at gmail dot com)
+ * @author Yang Fang (snoop dot fy at gmail dot com)
+ * @see TtlRunnable
+ * @see TtlCallable
+ * @see TtlExecutors
+ * @see TtlExecutors#getTtlExecutor(java.util.concurrent.Executor)
+ * @see TtlExecutors#getTtlExecutorService(java.util.concurrent.ExecutorService)
+ * @see TtlExecutors#getTtlScheduledExecutorService(java.util.concurrent.ScheduledExecutorService)
+ * @see TtlExecutors#getDefaultDisableInheritableThreadFactory()
+ * @see TtlExecutors#getDisableInheritableThreadFactory(java.util.concurrent.ThreadFactory)
+ * @see TtlForkJoinPoolHelper
+ * @see TtlForkJoinPoolHelper#getDefaultDisableInheritableForkJoinWorkerThreadFactory()
+ * @see TtlForkJoinPoolHelper#getDisableInheritableForkJoinWorkerThreadFactory(java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory)
+ * @see TtlAgent
+ * @since 0.10.0
+ */
+public class TransmittableThreadLocal
+ * Create a {@link TransmittableThreadLocal} instance with "Ignore-Null-Value Semantics".
+ * About "Ignore-Null-Value Semantics":
+ *
+ *
+ * This is a pragmatic design decision:
+ *
+ * So it's not recommended to use {@code null} value.
+ *
+ * But the behavior of "Ignore-Null-Value Semantics" is NOT compatible with
+ * {@link ThreadLocal} and {@link InheritableThreadLocal},
+ * you can disable this behavior/semantics via using constructor {@link #TransmittableThreadLocal(boolean)}
+ * and set parameter {@code disableIgnoreNullValueSemantics} instead.
+ *
+ * More info see Issue #157.
+ *
+ * @see #TransmittableThreadLocal(boolean)
+ */
+ public TransmittableThreadLocal() {
+ this(false);
+ }
+
+ /**
+ * Constructor, create a {@link TransmittableThreadLocal} with parameter {@code disableIgnoreNullValueSemantics}
+ * to control "Ignore-Null-Value Semantics".
+ *
+ * @param disableIgnoreNullValueSemantics disable "Ignore-Null-Value Semantics"
+ * @see #TransmittableThreadLocal()
+ * @since 2.11.3
+ */
+ public TransmittableThreadLocal(boolean disableIgnoreNullValueSemantics) {
+ this.disableIgnoreNullValueSemantics = disableIgnoreNullValueSemantics;
+ }
+
+ /**
+ * Computes the value for this transmittable thread-local variable
+ * as a function of the source thread's value at the time the task
+ * Object is created.
+ *
+ * This method is called from {@link TtlRunnable} or
+ * {@link TtlCallable} when it create, before the task is started.
+ *
+ * This method merely returns reference of its source thread value(the shadow copy),
+ * and should be overridden if a different behavior is desired.
+ *
+ * @since 1.0.0
+ */
+ public T copy(T parentValue) {
+ return parentValue;
+ }
+
+ /**
+ * Callback method before task object({@link TtlRunnable}/{@link TtlCallable}) execute.
+ *
+ * Default behavior is to do nothing, and should be overridden
+ * if a different behavior is desired.
+ *
+ * Do not throw any exception, just ignored.
+ *
+ * @since 1.2.0
+ */
+ protected void beforeExecute() {
+ }
+
+ /**
+ * Callback method after task object({@link TtlRunnable}/{@link TtlCallable}) execute.
+ *
+ * Default behavior is to do nothing, and should be overridden
+ * if a different behavior is desired.
+ *
+ * Do not throw any exception, just ignored.
+ *
+ * @since 1.2.0
+ */
+ protected void afterExecute() {
+ }
+
+ /**
+ * see {@link InheritableThreadLocal#get()}
+ */
+ @Override
+ public final T get() {
+ T value = super.get();
+ if (disableIgnoreNullValueSemantics || null != value) addThisToHolder();
+ return value;
+ }
+
+ /**
+ * see {@link InheritableThreadLocal#set}
+ */
+ @Override
+ public final void set(T value) {
+ if (!disableIgnoreNullValueSemantics && null == value) {
+ // may set null to remove value
+ remove();
+ } else {
+ super.set(value);
+ addThisToHolder();
+ }
+ }
+
+ /**
+ * see {@link InheritableThreadLocal#remove()}
+ */
+ @Override
+ public final void remove() {
+ removeThisFromHolder();
+ super.remove();
+ }
+
+ private void superRemove() {
+ super.remove();
+ }
+
+ private T copyValue() {
+ return copy(get());
+ }
+
+ // Note about the holder:
+ // 1. holder self is a InheritableThreadLocal(a *ThreadLocal*).
+ // 2. The type of value in the holder is WeakHashMap
+ *
+ *
+ *
+ *