代码改变世界

ThreadLocal实现原理和使用场景

2022-12-13 11:09  杭伟  阅读(91)  评论(0编辑  收藏  举报

ThreadLocal是线程本地变量,每个线程中都存在副本。

实现原理:

每个线程中都有一个ThreadLocalMap,而ThreadLocalMap中的key即是ThreadLocal。

 

 内存泄漏:

ThreadLocal变量存储在栈内存中,对应对象存储在堆内存中,这个指向是强引用关系。

同样,ThreadLocalMap变量存储在栈内存中,对应对象key-value存储在堆内存中,也是强引用关系。同时map中的key也指向了threadlocal。

如果ThreadLocal变量被置为空,但是map仍存在引用,会导致堆中的对象无法释放,java已将map中的key优化为弱引用(WeakReference)。

但是value本身也存在强引用的关系,value并不会被释放,所以依然存在内存泄漏问题。

解决方法是,手动调用threadlocal的remove方法。

 

使用:

 1 public class Main {
 2     private static ThreadLocal<Integer> tl = new ThreadLocal<>();
 3     public static void main(String[] args) throws InterruptedException{
 4         CountDownLatch c = new CountDownLatch(1);
 5         ThreadPoolExecutor tpe = new ThreadPoolExecutor(10, 20, 60L, TimeUnit.SECONDS,
 6                 new ArrayBlockingQueue<>(3));
 7         tpe.execute(new Runnable() {
 8             @Override
 9             public void run() {
10                 System.out.println(Thread.currentThread().getName());
11                 System.out.println(tl.get());
12                 tl.set(1);
13                 System.out.println(tl.get());
14                 tl.remove();
15                 c.countDown();
16             }
17         });
18         tpe.execute(new Runnable() {//模拟
19             @Override
20             public void run() {
21                try{c.await();}catch (InterruptedException e){};//让第一个线程先执行
22                 System.out.println(Thread.currentThread().getName());
23                 System.out.println(tl.get());
24                 tl.set(2);
25                 System.out.println(tl.get());
26                 tl.remove();
27             }
28         });
29         tpe.shutdown();
30     }
31 }

 

 

应用场景:

1,Spring多数据源配置的切换;

2,Spring事务注解的实现;

3,日志框架slf4j中的MDC类的实现

待更多补充。