TransmittableThreadLocal
pom引入:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.10.2</version>
</dependency>
TransmittableThreadLocal源码
继承InheritableThreadLocal
public class TransmittableThreadLocal<T> extends InheritableThreadLocal<T> {}
继承InheritableThreadLocal,说明可以实现父子线程的数据传递。
set方法
@Override
public final void set(T value) {
super.set(value);
// may set null to remove value
//value设置为null,也可以认为需要移除该TTL。
if (null == value) removeValue();
else addValue();
}
private void removeValue() {
//直接移除
holder.get().remove(this);
}
private void addValue() {
//添加TTL,使用WeakHashMap实现Set效果。
if (!holder.get().containsKey(this)) {
holder.get().put(this, null); // WeakHashMap supports null value.
}
}
holder说明
holder:通过holder持有所有线程的所有TTL变量,这样通过TTL变量,可以获取所有的TTL的值。
// Note about holder:
// 1. The value of holder is type Map<TransmittableThreadLocal<?>, ?> (WeakHashMap implementation),
// but it is used as *set*.
// Map虽然是WeakHashMap,但是却是按照set使用。。
// 2. WeakHashMap support null value.
// WeakHashMap支持value为null,因此只需要存入null即可,否则还需要创建个Object存储。
private static InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>> holder =
new InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>>() {
/**提供默认值,减少set时判断,否则还需要判断holder.get()!=null*/
@Override
protected Map<TransmittableThreadLocal<?>, ?> initialValue() {
return new WeakHashMap<TransmittableThreadLocal<?>, Object>();
}
/**重写childValue,表明当前InheritableThreadLocal并没有继承父线程的InheritableThreadLocal*/
@Override
protected Map<TransmittableThreadLocal<?>, ?> childValue(Map<TransmittableThreadLocal<?>, ?> parentValue) {
return new WeakHashMap<TransmittableThreadLocal<?>, Object>(parentValue);
}
};
查看holder,跟3 ThreadLocal-手写TransmittableThreadLocal 中的threadLocalsHolder是一样的,同样是持有所有线程的所有TTL变量,通过WeakHashMap实现Set的效果。
get方法
public final T get() {
T value = super.get();
if (null != value) addValue();
return value;
}
- 首先获取父类的get方法,毕竟最终存储还是在InheritableThreadLocalMap中。
- 其次判断获取的值是否为null。
a. 值不为空,添加记录,防止记录丢失。
addValue方法
private void addValue() {
if (!holder.get().containsKey(this)) {
holder.get().put(this, null); // WeakHashMap supports null value.
}
}
remove方法
@Override
public final void remove() {
removeValue();
super.remove();
}
private void removeValue() {
holder.get().remove(this);
}
- 先移除holder持有的TTL。
- 移除InheritableThreadLocal的值。
通过get、set、remove,TLL和自定义的MyTTL类似,只不过在holder存在差别。
TTL使用
public class TTLDemo {
private static ExecutorService executorService = Executors.newFixedThreadPool(1);
private static TransmittableThreadLocal currentUser = new TransmittableThreadLocal();
public static void main(String[] args) {
currentUser.set("jkf");
executorService.execute(TtlRunnable.get(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + currentUser.get());
}
}));
executorService.shutdown();
}
}
输出:
pool-1-thread-1:jkf
TtlRunnable
public final class TtlRunnable implements Runnable, TtlEnhanced {
private final AtomicReference<Object> capturedRef;
private final Runnable runnable;
private final boolean releaseTtlValueReferenceAfterRun;
private TtlRunnable(@Nonnull Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {
//备份业务线程的所有TTL
this.capturedRef = new AtomicReference<Object>(capture());
this.runnable = runnable;
this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;
}
@Override
public void run() {
Object captured = capturedRef.get();
if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {
throw new IllegalStateException("TTL value reference is released after run!");
}
//恢复业务TTL到池线程,同时返回池线程的TTL备份
Object backup = replay(captured);
try {
//运行业务
runnable.run();
} finally {
//复原池线程的TTL
restore(backup);
}
}
}
- 实现Runnable,可以提交到线程池。
- private final Runnable runnable:实际的业务Runnable,可以对原来的runnable进行包装。
- private final AtomicReference capturedRef:业务线程TTL的备份,创建TtlRunnable时,进行快照备份,这样就实现业务线程的TTL备份了。
Transmitter
transmiter搬运工,主要方法:
capture
该方法:直接备份当前线程的所有TTL和vlaue,也可以看做快照。
public static Object capture() {
Map<TransmittableThreadLocal<?>, Object> captured = new HashMap<TransmittableThreadLocal<?>, Object>();
//获取当前线程的所有TTL,并快照
for (TransmittableThreadLocal<?> threadLocal : holder.get().keySet()) {
captured.put(threadLocal, threadLocal.copyValue());
}
return captured;
}
replay
replay:恢复业务的TTL到池线程中。
public static Object replay(@Nonnull Object captured) {
@SuppressWarnings("unchecked")
//已经备份的业务TTL
Map<TransmittableThreadLocal<?>, Object> capturedMap = (Map<TransmittableThreadLocal<?>, Object>) captured;
//备份当前线程的TTL
Map<TransmittableThreadLocal<?>, Object> backup = new HashMap<TransmittableThreadLocal<?>, Object>();
//循环获取当前线程的所有TTL,并把当前线程打扫赶紧
for (Iterator<? extends Map.Entry<TransmittableThreadLocal<?>, ?>> iterator = holder.get().entrySet().iterator();
iterator.hasNext(); ) {
Map.Entry<TransmittableThreadLocal<?>, ?> next = iterator.next();
TransmittableThreadLocal<?> threadLocal = next.getKey();
//备份当前线程
// backup
backup.put(threadLocal, threadLocal.get());
// clear the TTL values that is not in captured
// avoid the extra TTL values after replay when run task
//移除当前线程其他TTL(业务线程没有的),打扫干净当前线程的TTL
if (!capturedMap.containsKey(threadLocal)) {
iterator.remove();
//注意此处会移除InheritableThreadLocalMap的值
threadLocal.superRemove();
}
}
// 把业务的TTL,copy到池线程中
// set values to captured TTL
setTtlValuesTo(capturedMap);
// call beforeExecute callback
doExecuteCallback(true);
return backup;
}
private static void setTtlValuesTo(@Nonnull Map<TransmittableThreadLocal<?>, Object> ttlValues) {
for (Map.Entry<TransmittableThreadLocal<?>, Object> entry : ttlValues.entrySet()) {
@SuppressWarnings("unchecked")
TransmittableThreadLocal<Object> threadLocal = (TransmittableThreadLocal<Object>) entry.getKey();
threadLocal.set(entry.getValue());
}
}
- 备份池线程的所有TTL。
- 清除池线程的其他TTL,打扫干净。
- 设置业务TTL到池线程。
restore
public static void restore(@Nonnull Object backup) {
@SuppressWarnings("unchecked")
Map<TransmittableThreadLocal<?>, Object> backupMap = (Map<TransmittableThreadLocal<?>, Object>) backup;
// call afterExecute callback
doExecuteCallback(false);
for (Iterator<? extends Map.Entry<TransmittableThreadLocal<?>, ?>> iterator = holder.get().entrySet().iterator();
iterator.hasNext(); ) {
Map.Entry<TransmittableThreadLocal<?>, ?> next = iterator.next();
TransmittableThreadLocal<?> threadLocal = next.getKey();
// clear the TTL values that is not in backup
// avoid the extra TTL values after restore
//清除不在备份中的TTL,防止出现多余的TTL
if (!backupMap.containsKey(threadLocal)) {
iterator.remove();
threadLocal.superRemove();
}
}
// restore TTL values
//恢复池线程的原来TTL
setTtlValuesTo(backupMap);
}
TtlExecutors
因Runnable任务的提交位置比较多,或者TtlRunnable包装不太方便,因此可以考虑从线程池角度处理,对现有的线程池进行增强。
public final class TtlExecutors {
/**
* {@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}.
*/
@Nullable
public static ExecutorService getTtlExecutorService(@Nullable ExecutorService executorService) {
if (TtlAgent.isTtlAgentLoaded() || executorService == null || executorService instanceof TtlEnhanced) {
return executorService;
}
return new ExecutorServiceTtlWrapper(executorService);
}
}
class ExecutorServiceTtlWrapper extends ExecutorTtlWrapper implements ExecutorService, TtlEnhanced {
private final ExecutorService executorService;
ExecutorServiceTtlWrapper(@Nonnull ExecutorService executorService) {
super(executorService);
this.executorService = executorService;
}
//对submit方法进行增强
public <T> Future<T> submit(@Nonnull Callable<T> task) {
return executorService.submit(TtlCallable.get(task));
}
}
class ExecutorTtlWrapper implements Executor, TtlEnhanced {
private final Executor executor;
ExecutorTtlWrapper(@Nonnull Executor executor) {
this.executor = executor;
}
/**对execute方法进行增强*/
@Override
public void execute(@Nonnull Runnable command) {
executor.execute(TtlRunnable.get(command));
}
}
上述ExecutorServiceTtlWrapper就是对execute和submit方法进行增强,通过TtlRunnable和TtlCallable,进行包装,一劳永逸的解决ThreadLocal/InheritableThreadLocal切换为TTL。
holder为什么是InheritableThreadLocal
TransmittableThreadLocal的holder是InheritableThreadLocal,而自定义用的是ThreadLocal。
采用InheritableThreadLocal作为holder,主要是解决holder的继承问题,因为如果holder为ThreadLocal,主线程创建子线程,子线程提交任务到线程池时,因为holder的无法传递,导致子线程提交任务时,holder为空。无法备份数据,这样TTL的作用就丧失了。
或者也可以从TransmittanbleThreadLocal宏观说起,TransmittableThreadLocal 继承InheritableThreadLocal,holder使用ThreadLocal,两者的传递性质不同,肯定会导致一个传递了,另一个丢了,类似于:ThreadLocalMap和Thread是同生命周期,而ThreadLocal的生命周期缺不是。
示例:
public class TTLDemo {
//创建holder
private static ThreadLocal<Map<TransmittableThreadLocal<?>, ?>> holder =
new ThreadLocal<Map<TransmittableThreadLocal<?>, ?>>() {
@Override
protected Map<TransmittableThreadLocal<?>, ?> initialValue() {
return new WeakHashMap<TransmittableThreadLocal<?>, Object>();
}
// @Override
// protected Map<TransmittableThreadLocal<?>, ?> childValue(Map<TransmittableThreadLocal<?>, ?> parentValue) {
// return new WeakHashMap<TransmittableThreadLocal<?>, Object>(parentValue);
// }
};
public static void main(String[] args) {
TransmittableThreadLocal ttl = new TransmittableThreadLocal();
ttl.set("jkf");
mockSet(ttl);
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + ttl.get());
//类似于TTlRunnable备份,获取当前线程所有的TTL变量,
//但是因为holder是ThreadLocal,子线程无法获取父线程的holder数据
//此时备份子线程的ttl变量,就备份了个寂寞
for (Map.Entry<TransmittableThreadLocal<?>, ?> entry : holder.get().entrySet()) {
System.out.println(entry.getKey().get());
}
System.out.println("holder的ttl数量:"+holder.get().size());
}
}).start();
while (true) {
}
}
private static void mockSet(TransmittableThreadLocal ttl) {
WeakHashMap map = new WeakHashMap();
map.put(ttl, null);
holder.set(map);
}
}
输出:
Thread-1:jkf
holder的ttl数量:0
DisableInheritableThreadFactoryWrapper
TTL继承自InheritableThreadLocal,因此InheritableThreadLocal应用于线程池的缺陷,TTL也具有,例如:数据泄漏,当业务线程提交任务时,线程池正好需要创建新线程来执行任务,那么InheritableThreadLocal就会从业务线程,被copy到池线程中,存在一定的数据泄漏。
因为池线程是与业务脱钩的,因此上述情况需要避免。主要通过创建线程时,先移除并备份业务线程的TTL,创建线程,然后再复原业务线程的TTL。
DisableInheritableThreadFactoryWrapper就是解决上述问题。
class DisableInheritableThreadFactoryWrapper implements DisableInheritableThreadFactory {
final ThreadFactory threadFactory;
public DisableInheritableThreadFactoryWrapper(@Nonnull ThreadFactory threadFactory) {
this.threadFactory = threadFactory;
}
@Override
public Thread newThread(Runnable r) {
final Object backup = TransmittableThreadLocal.Transmitter.clear();
try {
return threadFactory.newThread(r);
} finally {
TransmittableThreadLocal.Transmitter.restore(backup);
}
}
@Nonnull
@Override
public ThreadFactory unwrap() {
return threadFactory;
}
}
- DisableInheritableThreadFactory extends ThreadFactory,因此实现newThread方法。
- newThread:
a. Transmitter.clear():清空所有的业务TTL,同时返回备份。
b. 调用实际的ThreadFactory创建线程。
c. 利用备份数据,restore业务线程的TTL。
使用方式
单独setThreadFactory
private static ExecutorService executorService;
static {
executorService = Executors.newFixedThreadPool(1);
((ThreadPoolExecutor) executorService).setThreadFactory(TtlExecutors.getDisableInheritableThreadFactory(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
}));
}
单独设置ThreadFactory,创建后立即设置。
ThreadFactory作为入参
new ThreadPoolExecutor(1, 2, 10,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(), TtlExecutors.getDisableInheritableThreadFactory(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
}));
手动创建线程池时,可以直接指定ThreadFactory。