ThreadLocal,InheritableThreadLocal,TTL全解
ThreadLocal,InheritableThreadLocal,TTL全解
一、ThreadLoal 详解
ThreadLocal 是保存线程的使用变量。 ThreadLocal具体方法如下:
public class ThreadLocal<T> { /** * 1.8以后提供的,返回一个有初始值的ThreadLocal */ public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) { return new SuppliedThreadLocal<>(supplier); } /** * 获取当前线程保存的变量 */ public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } /** * 设置当前线程的值 */ public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } /** * 清除当前线程的值:当前线程退出时,最后要调用一下清除方法。 */ public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); } /** * 创建一个ThreadLocalMap,多个线程保存变量个关键的关键 */ void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } }
通过以代码可以看到ThreadLocalMap是每个线程持有的。所以保证线程隔离。ThreadLocalMap中key使用的使用的弱引用,在相同GC时,就会被清理掉。threadLocal生命周期里会尽可能的保证不出现内存泄漏的问题,达到安全的状态。 那么ThreadLocal会有内存泄露的问题吗?答案是会的。避免内存泄露的方法,是在使用完ThreadLocal后,要调用remove方法,将其清除掉。
二、InheritableThreadLocal 详解
InheritableThreadLocal 用于子线程创建时,自动继承父线程的ThreadLocal变量。
可以看出InheritableThreadLocal 是继承ThreadLocal并重写了其中的3个方法。实现子线程获取父线程的变量,是在Thread的初始化的时候。 默认是TRUE,也就是 初始化的时候,将父线程的所以变量都遍历复制一遍,这也子线程就自动的获取到父线程的值了。 注意:InheritableThreadLocal在线程池使用的时候,就会失效。如果想用线程池,可以考虑使用阿里的TTL
三、阿里TTL的使用
阿里的transmittable-thread-local简称TTL,TTL继承并加强InheritableThreadLocal类。 典型使用场景 分布式跟踪系统 应用容器或上层框架跨应用代码给下层SDK传递信息 日志收集记录系统上下文 使用类TransmittableThreadLocal来保存上下文,并跨线程池传递。TransmittableThreadLocal继承InheritableThreadLocal,使用方式也类似。比InheritableThreadLocal,添加了protected方法copy,用于定制 任务提交给线程池时的上下文传递到 任务执行时时的拷贝行为,缺省是传递的是引用。
可以说TTL是InheritableThreadLocal的加强版。使用方法:
- 使用com.alibaba.ttl.TtlRunnable和com.alibaba.ttl.TtlCallable来修饰传入线程池的Runnable和Callable。
- 省去每次Runnable和Callable传入线程池时的修饰,这个逻辑可以在线程池中完成。 通过工具类com.alibaba.ttl.threadpool.TtlExecutors完成,有下面的方法: getTtlExecutor:修饰接口Executor getTtlExecutorService:修饰接口ExecutorService ScheduledExecutorService:修饰接口ScheduledExecutorService
- 使用Java Agent来修饰JDK线程池实现类
总结
通过以上分析,结合不同的场景,应用不同的ThreadLocal,达到自己的目的。