ThreadLocal 深入了解

简介: ThreadLocal 深入了解

ThreadLocal用于提供线程局部变量,每个线程有拥有其独立初始化的变量副本。当线程消失时,其线程本地实例的所有副本都将被垃圾回收。

ThreadLocal<Object> threadLocal = new ThreadLocal<>();


Thread类中定义了类型为ThreadLocal.ThreadLocalMap的成员变量

/*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;


ThreadLocal定义

static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            /** The value associated with this ThreadLocal. */
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
}


内存中关系如下图表示


image.png


通过源码可以看出


1、new ThreaLocal()会在堆内存中创建一个ThreadLocal对象,对应的应用在栈中。


2、ThreadLocalMap是Thread类的成员变量,key是ThreadLocal对象,Value是当前线程的局部变量。


key通过弱引用指向ThreadLocal对象,这里为什么会设计成弱引用(关于弱引用及软引用、强引用的关系参考上一篇文章),是因为ThreadLocal的设计者考虑到线程往往是以线程池的形式存在,这样线程的生命周期就会很长,Thread对象->ThreadLocalMap->Entry这条引用链会一直存在,因为是强引用,GC时不会被回收,如果key强应用ThreadLocal对象,那么key引用的对象也不会被回收,容易造成内存的泄露。而设计成弱引用后,只要ThreadLocal->ThreadLocal对象的这条强引用关系消失,则GC的时候threadlocal对象就会被回收。而ThreadLocal的作用域是当前线程,所以当当前线程结束时,ThreadLocal对象将会在下次GC时被回收掉。


ThreadLocalMap数据结构


ThreadLocal的get/set都是通过ThreadLocalMap实现,而ThreadLocalMap内部跟Map类似,也是通过数组实现。数组元素是Entry对象,key值是ThreadLocal对象,value值存放线程变量。

static class ThreadLocalMap {
        static class Entry extends WeakReference<ThreadLocal<?>> {
            Object value;
            Entry(ThreadLocal<?> k, Object v) {
                super(k);
                value = v;
            }
        }
        //初始容量大小
        private static final int INITIAL_CAPACITY = 16;
        //元素存放数组
        private Entry[] table;
        //数组元素个数
        private int size = 0;
        //扩容阈值
        private int threshold; // Default to 0


ThreadLocalMap Hash冲突解决办法


我们知道在Map中,如果Hash冲突,会存放为链表结构,当链表长度超过一定阈值时(超过8)会转换为红黑树,但是ThreadLocal不同,即没用链表也没用红黑树,而是采用了线性探测的方式,即先找到需要存放的位置,如果该位置不为空,则根据一定算法计算步长,线性寻址下个位置。


image.png

private void set(ThreadLocal<?> key, Object value) {
            Entry[] tab = table;
            int len = tab.length;
            // 计算要存放元素在数组中的位置,上面第一步
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 // 循环结束条件是元素为null,即找到存放位置
                 e != null;
                 // 根据固定算法计算循环步长 
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
                //key相同,则更新值,并退出循环
                if (k == key) {
                    e.value = value;
                    return;
                }
                //如果key为空,做一些清理操作
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            // 找到合适的槽位,并new一个新的Entry
            tab[i] = new Entry(key, value);
            int sz = ++size;
            //计算是否需要扩容
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }


相关文章
|
3月前
|
Java 测试技术 索引
ThreadLocal详解
文章详细讨论了Java中的`ThreadLocal`,包括它的基本使用、定义、内部数据结构`ThreadLocalMap`、主要方法(set、get、remove)的源码解析,以及内存泄漏问题和避免策略。`ThreadLocal`提供了线程局部变量,确保多线程环境下各线程变量的独立性,但不当使用可能导致内存泄漏,因此建议在不再需要`ThreadLocal`变量时调用其`remove`方法。
109 2
ThreadLocal详解
|
5月前
|
Java
ThreadLocal 场景题
ThreadLocal 场景题
36 1
|
6月前
|
存储 Java 数据管理
ThreadLocal的使用
`ThreadLocal`是Java中的线程局部变量工具,确保每个线程都有自己的变量副本,互不干扰。适用于保持线程安全性数据和跨方法共享数据。基本用法包括创建实例、设置和获取值以及清除值。例如,创建ThreadLocal对象后,使用`.set()`设置值,`.get()`获取值,`.remove()`清除值。注意ThreadLocal可能引起内存泄漏,应适时清理,并谨慎使用以避免影响代码可读性和线程安全性。它是多线程编程中实现线程局部数据管理的有效手段。
88 10
|
缓存 安全 Java
浅谈ThreadLocal
浅谈ThreadLocal
148 0
|
存储 Java
|
存储 SQL Java
ThreadLocal的其他应用
request对象跟PageHelper
101 0
|
存储 Java 数据库连接
对ThreadLocal的一点了解
ThreadLocal是线程变量,它为每个线程提供单独的存储空间。其主要作用是做线程间的数据隔离,也可以用于在同一个线程间方便地进行数据共享。(对于多线程资源共享,加锁机制采用“时间换空间”,ThreadLocal采用“空间换时间”)
127 0
|
存储 Java
对threadlocal了解多少?
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。如果想实现每一个线程都有自己的专属本地变量该如何解决呢? JDK 中提供的 ThreadLocal 类正是为了解决这样的问题。 ThreadLocal 类主要解决的就是让每个线程绑定自己的值,可以将 ThreadLocal 类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。
|
存储 安全 Java
我把 ThreadLocal 能问的,都写了(上)
我把 ThreadLocal 能问的,都写了(上)
我把 ThreadLocal 能问的,都写了(上)
|
Java 应用服务中间件
我把 ThreadLocal 能问的,都写了(下)
我把 ThreadLocal 能问的,都写了(下)
我把 ThreadLocal 能问的,都写了(下)