有状态实例线程安全化、上下文隐式传参
ThreadLocalMap:key为ThreadLocal,value为需要存放的值。
如果ThreadLocalRef置为null,由于只存在弱引用,没有强引用,所以GC会去回收ThreadLocal。因此ThreadLocalMap中key被回收了,value被"遗漏了",导致内存泄漏。
1、ThreadLocal和WeakReference都是在jdk1.2版本引入的。当时没有remove方法,也没有线程池,基本不会发生内存泄漏。
2、ThreadLocal通过判断key是否为null,对entry进行置换,避免内存泄漏。
3、Executor框架以及ThreadLocal#remove方法都是在jdk1.5版本引入的。
1、继承自ThreadLocal,在创建线程的时候实现父子线程之间的参数传递,直接浅拷贝父线程的inheritabeThreadLocals。
2、jdk1.2版本引入的,不能解决jdk1.5版本引入Executor后线程池的参数传递问题。
1.capture方法:抓取线程(线程A)的所有TTL值。
2.replay方法:在另一个线程(线程B)中,回放在capture方法中抓取的TTL值,并返回 回放前TTL值的备份
3.restore方法:恢复线程B执行replay方法之前的TTL值(即备份值)
InheritableThreadLocal上下文传递时机
父线程在设置ITL值后,创建子线程时,通过浅拷贝的形式传递给子线程,见InheirtableThreadLocal说明。
:创建线程时传递ITL值。
TransmittableThreadLocal上下文传递时机
父线程在创建任务时将通过抓取当前线程的所有TTL值,在子线程执行任务过程中进行回放。并且在子线程任务执行结束后恢复子线程原来的TTL值。
为什么要恢复子线程原来的TTL值呢?
1、线程池设置了CallerRunsPolicy,在线程池触发拒绝策略机制时,任务会由Caller线程执行。如果只是remove掉TTL值的话,会导致Caller线程的上下文丢失。
2、使用ForkJoinPool的场景,ForkJoinTask会在调用线程中直接执行。
重点:创建任务时,传递TTL值。
还原思路跟重放思路类似,这里只分析重放思路。
TransmittableThreadLocal 使用
Maven引入
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>transmittable-thread-local</artifactId>
- <version>2.11.5</version> //最新版本
- </dependency>
- public class TransmittableThreadPoolTest {
-
- public static TransmittableThreadLocal<Stu> threadLocal = new TransmittableThreadLocal();
- public static ThreadPoolExecutor executorService = new ThreadPoolExecutor(1, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(4));
-
- public static void main(String[] args) throws InterruptedException {
-
- threadLocal.set(new Stu(1));
- ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(executorService);
- // ttlExecutorService = executorService;
-
- for (int i = 0; i < 1; i++) {
-
- ttlExecutorService.execute(new Runnable() {
- @Override
- public void run() {
- System.out.println(threadLocal.get());
- }
- });
- }
-
- Thread.sleep(100);
- // threadLocal.set(new Stu(2));
- for (int i = 0; i < 1; i++) {
-
- ttlExecutorService.execute(new Runnable() {
- @Override
- public void run() {
- System.out.println(threadLocal.get());
- }
- });
- }
- }
- }