【Java】浅谈ThreadLocal

发布于:2025-08-19 ⋅ 阅读:(13) ⋅ 点赞:(0)

一,概述

ThreadLocal,其作用是实现线程独享数据,用于隔离每个线程对于同一个值的访问,核心方法只有三个:

ThreadLocal#set 设置线程独享数据

ThreadLocal#get 获得线程独享数据

ThreadLocal#remove清除线程独享数据

本文主要谈谈ThreadLocal基本使用、实现原理、以及使用注意事项的讨论。

二,实例

public class ThreadLocalMain {


    //定义一个ThreadLocal
    public static final ThreadLocal<Integer> threadLocal = new ThreadLocal<>() {
        @Override
        protected Integer initialValue() {
            //重写initialValue方法,否则默认返回null作为初始值
            System.out.println("init value for thread:" + Thread.currentThread().getName());
            return Thread.currentThread().hashCode();
        }
    };
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                //线程中get
                System.out.println(threadLocal.get());
                //线程中set
                threadLocal.set(1);
                //线程中remove
                threadLocal.remove();
            }).start();
        }
    }
}

三,原理

ThreadLocal既然线程数据独享,则必定有一个线程->数据映射的map,这个map要么放置在Thread、要么放置在ThreadLocal。显然放在Thread合理,因为ThreadLocal实例存在多个,ThreadLocal自身可以作为一个key,绑定到每个Thread的map中,所需创建的map较少,且不改变Thread的引用。如果将map放置到ThreadLocal,显然ThreadLocal会引用到Thread,不利于Thread的gc。

关于在于怎么设计,ThreadLocal本身即为一个key。

在java实现中,这个map放置在Thread

Thread.map = ThreadLocal.ThreadLocalMap threadLocals;

这是一个数组实现的map,具体实现此处不赘述。

1,get

get只暴露如下方法

以上逻辑分三步走,

1,拿到线程map

2,将ThreadLocal实例作为key,从map中取值并返回

3,如果未set值,则调用setInitialValue方法初始化

getMap方法实现如下,很简单,直接取thread#threadLocals

对于map为null或未设置值的情况,会走setInitialValue,跟进看下逻辑

如果map存在直接set即可,否则通过creatMap创建map,

创建方式很简单,传入初始key和value即可,

这样,Thread上下文中就可通过Thread#threadLocal获得ThreadLocal作为key的value了。

2,set

set方法与setInitialValue方法逻辑类似,就不赘述了

核心在于set中有一个关于引用的特殊处理,能规避一些内存泄漏,咱们看下

2 是对ThreadLocal是否gc的判断,如果已经gc,refersTo返回false。

3 如果ThreadLocal已经gc,则重新新建一个引用关系,赋值。

Entry声明如下

可以看到,ThreadLocal作为key是以弱引用方式,传入到Entry中,即Map对应散列表Node。

但set的值,仍是强引用保存到Thread#threadLocals#Entry[]中。以上只对ThreadLocal本身做了内存泄漏防护,对保存的value如果不及时remove,是会一直存在于Thread中,直至Thread销毁

3,remove

remove比较简单,不赘述