package com.alibaba.ttl; import java.util.*; import java.util.concurrent.Callable; import java.util.function.Supplier; import java.util.logging.Level; import java.util.logging.Logger; /** * {@link TransmittableThreadLocal} can transmit value from the thread of submitting task to the thread of executing task. *
* Note: {@link TransmittableThreadLocal} extends {@link java.lang.InheritableThreadLocal},
* so {@link TransmittableThreadLocal} first is a {@link java.lang.InheritableThreadLocal}.
*
* @author Jerry Lee (oldratlee at gmail dot com)
* @see TtlRunnable
* @see TtlCallable
* @since 0.10.0
*/
public class TransmittableThreadLocal
* This method merely returns reference of its source thread value, and should be overridden
* if a different behavior is desired.
*
* @since 1.0.0
*/
protected T copy(T parentValue) {
return parentValue;
}
/**
* Callback method before task object({@link TtlRunnable}/{@link TtlCallable}) execute.
*
* Default behavior is 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 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() {
}
@Override
public final T get() {
T value = super.get();
if (null != value) {
addValue();
}
return value;
}
@Override
public final void set(T value) {
super.set(value);
if (null == value) { // may set null to remove value
removeValue();
} else {
addValue();
}
}
@Override
public final void remove() {
removeValue();
super.remove();
}
void superRemove() {
super.remove();
}
T copyValue() {
return copy(get());
}
private static InheritableThreadLocal
* {@link Transmitter} is internal manipulation api for framework/middleware integration;
* In general, you will never use it in the biz/application code!
*
* Below is the example code:
*
*
* see the implementation code of {@link TtlRunnable} and {@link TtlCallable} for more actual code sample.
*
* Below is the example code:
*
*
* The reason of providing 2 util methods is the different {@code throws Exception} type from biz logic({@code lambda}):
*
* If you has the different {@code throws Exception},
* you can define your own util method with your own {@code throws Exception} type function interface({@code lambda}).
*
* @author Yang Fang (snoop dot fy at gmail dot com)
* @author Jerry Lee (oldratlee at gmail dot com)
* @see TtlRunnable
* @see TtlCallable
* @since 2.3.0
*/
public static class Transmitter {
/**
* Capture all {@link TransmittableThreadLocal} values in current thread.
*
* @return the captured {@link TransmittableThreadLocal} values
* @since 2.3.0
*/
public static Object capture() {
Map
*
* ///////////////////////////////////////////////////////////////////////////
* // in thread A, capture all TransmittableThreadLocal values of thread A
* ///////////////////////////////////////////////////////////////////////////
*
* Object captured = Transmitter.capture(); // (1)
*
* ///////////////////////////////////////////////////////////////////////////
* // in thread B
* ///////////////////////////////////////////////////////////////////////////
*
* // replay all TransmittableThreadLocal values from thread A
* Object backup = Transmitter.replay(captured); // (2)
* try {
* // your biz logic, run with the TransmittableThreadLocal values of thread B
* System.out.println("Hello");
* // ...
* return "World";
* } finally {
* // restore the TransmittableThreadLocal of thread B when replay
* Transmitter.restore(backup); (3)
* }
*
* Of course, {@link #replay(Object)} and {@link #restore(Object)} operation can be simplified
* by util methods {@link #runCallableWithCaptured(Object, Callable)} or {@link #runSupplierWithCaptured(Object, Supplier)}
* and the adorable {@code Java 8 lambda syntax}.
*
*
* ///////////////////////////////////////////////////////////////////////////
* // in thread A, capture all TransmittableThreadLocal values of thread A
* ///////////////////////////////////////////////////////////////////////////
*
* Object captured = Transmitter.capture(); // (1)
*
* ///////////////////////////////////////////////////////////////////////////
* // in thread B
* ///////////////////////////////////////////////////////////////////////////
*
* String result = runSupplierWithCaptured(captured, () -> {
* // your biz logic, run with the TransmittableThreadLocal values of thread A
* System.out.println("Hello");
* ...
* return "World";
* }); // (2) + (3)
*
*
*