ThreadLocal详解

简介: ThreadLocal详解

ThreadLocal是什么

线程本地变量。当使用 ThreadLocal 维护变量时, ThreadLocal 为每个使用该变量的线程提供独立的 变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程。

ThreadLocal原理

每个线程都有一个 ThreadLocalMap ( ThreadLocal 内部类),Map中元素的键为 ThreadLocal ,而 值对应线程的变量副本。

image.png

调用 threadLocal.set() -->调用 getMap(Thread) -->返回当前线程的 ThreadLocalMap --> map.set(this, value) ,this是 threadLocal 本身。源码如下

publicvoidset(Tvalue) {
Threadt=Thread.currentThread();
ThreadLocalMapmap=getMap(t);
if (map!=null)
map.set(this, value);
elsecreateMap(t, value);
}
ThreadLocalMapgetMap(Threadt) {
returnt.threadLocals;
}
voidcreateMap(Threadt, TfirstValue) {
t.threadLocals=newThreadLocalMap(this, firstValue);
}

调用 get() -->调用 getMap(Thread) -->返回当前线程的 ThreadLocalMap -- > map.getEntry(this) ,返回 value 。源码如下:

publicTget() {
Threadt=Thread.currentThread();
ThreadLocalMapmap=getMap(t);
if (map!=null) {
ThreadLocalMap.Entrye=map.getEntry(this);
if (e!=null) {
@SuppressWarnings("unchecked")
Tresult= (T)e.value;
returnresult;
        }
    }
returnsetInitialValue();
}

threadLocals 的类型 ThreadLocalMap 的键为 ThreadLocal 对象,因为每个线程中可有多个 threadLocal 变量,如 longLocal 和 stringLocal 。

publicclassThreadLocalDemo {
ThreadLocal<Long>longLocal=newThreadLocal<>();
publicvoidset() {
longLocal.set(Thread.currentThread().getId());
    }
publicLongget() {
returnlongLocal.get();
    }
publicstaticvoidmain(String[] args) throwsInterruptedException {
ThreadLocalDemothreadLocalDemo=newThreadLocalDemo();
threadLocalDemo.set();
System.out.println(threadLocalDemo.get());
Threadthread=newThread(() -> {
threadLocalDemo.set();
System.out.println(threadLocalDemo.get());
        });
thread.start();
thread.join();
System.out.println(threadLocalDemo.get());
    }
}

ThreadLocal 并不是用来解决共享资源的多线程访问问题,因为每个线程中的资源只是副本,不会共 享。因此 ThreadLocal 适合作为线程上下文变量,简化线程内传参

ThreadLocal内存泄漏的原因?

每个线程都有⼀个 ThreadLocalMap 的内部属性,map的key是 ThreaLocal ,定义为弱引用,value是 强引用类型。垃圾回收的时候会⾃动回收key,而value的回收取决于Thread对象的生命周期。一般会通 过线程池的方式复用线程节省资源,这也就导致了线程对象的生命周期比较长,这样便一直存在一条强 引用链的关系: Thread --> ThreadLocalMap --> Entry --> Value ,随着任务的执行,value就有可能 越来越多且无法释放,最终导致内存泄漏。

解决⽅法:每次使⽤完 ThreadLocal 就调⽤它的 remove() ⽅法,手动将对应的键值对删除,从⽽避免 内存泄漏。

ThreadLocal使用场景有哪些?

ThreadLocal 适用场景:每个线程需要有自己单独的实例,且需要在多个方法中共享实例,即同时满足 实例在线程间的隔离与方法间的共享,这种情况适合使用 ThreadLocal 。比如Java web应用中,每个线 程有自己单独的 Session 实例,就可以使用 ThreadLocal 来实现。

相关文章
|
6月前
|
Java
ThreadLocal 场景题
ThreadLocal 场景题
37 1
|
存储
ThreadLocal
ThreadLocal
53 0
|
存储 安全 Java
ThreadLocal介绍和应用
ThreadLocal介绍和应用
70 0
|
缓存 安全 Java
浅谈ThreadLocal
浅谈ThreadLocal
149 0
|
存储 Java
|
存储 SQL Java
ThreadLocal的其他应用
request对象跟PageHelper
104 0
|
存储 分布式计算 安全
什么是ThreadLocal?
这篇文章是慕课网上一门免费课程《ThreadLocal》的观后总结。这门课将ThreadLocal讲得非常清晰易懂,又深入底层原理和设计思想,是我看过的最好的ThreadLocal的资料,现在把用自己的话,把它整理成文字版本。 总共预计产出四篇文章,这是第一篇。
267 3
|
存储 安全 Java
ThreadLocal 使用详解
ThreadLocal 是线程本地变量。当使用 ThreadLocal 维护变量时,ThreadLocal 为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程
546 0
|
存储 Java
ThreadLocal理解
ThreadLocal理解
289 0
ThreadLocal理解