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 来实现。

相关文章
|
16天前
|
Java 测试技术 索引
ThreadLocal详解
文章详细讨论了Java中的`ThreadLocal`,包括它的基本使用、定义、内部数据结构`ThreadLocalMap`、主要方法(set、get、remove)的源码解析,以及内存泄漏问题和避免策略。`ThreadLocal`提供了线程局部变量,确保多线程环境下各线程变量的独立性,但不当使用可能导致内存泄漏,因此建议在不再需要`ThreadLocal`变量时调用其`remove`方法。
65 2
ThreadLocal详解
|
2月前
|
存储 Java
ThreadLocal应用及理解
ThreadLocal应用及理解
31 10
|
3月前
|
Java
ThreadLocal 场景题
ThreadLocal 场景题
20 1
|
4月前
|
存储 Java 数据管理
ThreadLocal的使用
`ThreadLocal`是Java中的线程局部变量工具,确保每个线程都有自己的变量副本,互不干扰。适用于保持线程安全性数据和跨方法共享数据。基本用法包括创建实例、设置和获取值以及清除值。例如,创建ThreadLocal对象后,使用`.set()`设置值,`.get()`获取值,`.remove()`清除值。注意ThreadLocal可能引起内存泄漏,应适时清理,并谨慎使用以避免影响代码可读性和线程安全性。它是多线程编程中实现线程局部数据管理的有效手段。
75 10
|
存储 Java
|
存储 SQL Java
ThreadLocal的其他应用
request对象跟PageHelper
91 0
|
存储 Java 数据库连接
对ThreadLocal的一点了解
ThreadLocal是线程变量,它为每个线程提供单独的存储空间。其主要作用是做线程间的数据隔离,也可以用于在同一个线程间方便地进行数据共享。(对于多线程资源共享,加锁机制采用“时间换空间”,ThreadLocal采用“空间换时间”)
119 0
|
存储 分布式计算 安全
什么是ThreadLocal?
这篇文章是慕课网上一门免费课程《ThreadLocal》的观后总结。这门课将ThreadLocal讲得非常清晰易懂,又深入底层原理和设计思想,是我看过的最好的ThreadLocal的资料,现在把用自己的话,把它整理成文字版本。 总共预计产出四篇文章,这是第一篇。
250 3
|
存储 Java
对threadlocal了解多少?
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢? JDK 中提供的 ThreadLocal 类正是为了解决这样的问题。 ThreadLocal 类主要解决的就是让每个线程绑定自己的值,可以将 ThreadLocal 类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。