ThreadLocal使用详解-从源码层面分析

从demo入手看效果

代码Demo

    static ThreadLocal tl1 = new ThreadLocal();
    static ThreadLocal tl2 = new ThreadLocal();
    static ThreadLocal tl3 = new ThreadLocal();

    public static void main(String[] args) {
        tl1.set("123");
        tl2.set("456");
        tl3.set("4586");
        Thread t1 = new Thread(() -> {
        System.out.println("t1:tl1-before:" + tl1.get());
            System.out.println("t1:tl2-before:" + tl2.get());
            System.out.println("t1:tl3-before:" + tl3.get());
            ThreadLocal tl4 = new ThreadLocal();
            tl1.set("1231");
            tl2.set("4561");
            tl3.set("12312");
            tl4.set("123121231212312");
            System.out.println("t1:tl1-" + tl1.get());
            System.out.println("t1:tl2-" + tl2.get());
            System.out.println("t1:tl3-" + tl3.get());
            System.out.println("t1:tl4-" + tl4.get());
        });
        t1.start();

        Thread.sleep(5000);
        System.out.println("main:tl1-" + tl1.get());
        System.out.println("main:tl2-" + tl2.get());
        System.out.println("main:tl3-" + tl3.get());

执行结果:

t1:tl1-before:null
t1:tl2-before:null
t1:tl3-before:null
t1:tl1-1231
t1:tl2-4561
t1:tl3-12312
t1:tl4-123121231212312
main:tl1-123
main:tl2-456
main:tl3-4586

结论:
根据结果可以发现 相同的ThreadLocal 在main线程和t1 线程存入不同的数据,拿到的结果不一样,即使主线程先在ThreadLocal执行set方法,在t1线程中还是获取为空,可以说明在T1线程内部获取ThreadLocal是获取不到main线程的,因此可以证明实现了线程隔离。

源码分析

Thread:

 ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocal类中包含一个静态类 ThreadLocalMap,是一个定制化的哈希表,用于存储线程的私有数据。键为ThreadLocal对象(弱引用),值为线程的局部变量(强引用)
在这里插入图片描述
ThreadLocal的set方法源码:

设置该线程局部变量的当前线程副本到指定的值。大多数子类都不需要这样做重写此方法,仅依赖于{@link #initialValue}方法设置线程局部变量的值。
 public void set(T value) {
        Thread t = Thread.currentThread();//
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
    }

在上面set方法里先获取到执行该方法的线程对象,再基于此对象去获取该线程的ThreadLocalMap 来实现线程间的隔离数据
getMap

获取与ThreadLocal相关联的映射
ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

createMap:创建该线程的ThreadLocalMap

void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

new ThreadLocalMap(this, firstValue)

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
            table = new Entry[INITIAL_CAPACITY];
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

**set方法执行结论:**先获取到执行该方法的线程对象,然后基于这个对象获取ThreadLocalMap,进行实例化,赋值。赋值的key就是ThreadLocal,虽然ThreadLocal在多线程中复用,但是实际存储数据的是ThreadLocalMap,这个ThreadLocalMap是和Thread绑定的

get方法

public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

getMap

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

setInitialValue

private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            map.set(this, value);
        } else {
            createMap(t, value);
        }
        if (this instanceof TerminatingThreadLocal) {
            TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this);
        }
        return value;
    }

get方法执行结论: 先拿到执行方法的当前线程 根据当前线程去获取map,有就以ThreadLocal为key去获取value。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值