Java ThreadLocal和InheritableThreadLocal源码分析

本文深入剖析Java中ThreadLocal及InheritableThreadLocal的工作原理,包括构造器、init方法、set/get/remove操作,以及如何在子线程中继承父线程的ThreadLocal变量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 概述

在上一篇Java ThreadLocalMap 源码解析的基础上,本文开始分析ThreadLocal相关源码。
参照下方UML图,可以看出:
1)Thread类关联ThreadLocalMap对象,分别对应成员变量threadLocals和inheritableThreadLocals;
2)ThreadLocal依赖Thread对象,主要表现为操作Thread对象的ThreadLocalMap对象;
3)InheritableThreadLocal类继承ThreadLocal类,主要用于实现子线程继承父线程的ThreadLocalMap对象inheritableThreadLocals。
在这里插入图片描述

2. Thread

2.1 Constructors

如下源码,Thread的构造器方法全部调用了init方法。其中第三个构造器最后一个参数false表示不继承父线程的ThreadLocalMap对象,其余构造器全部默认继承父线程的ThreadLocalMap对象。

    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }
    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }    
    Thread(Runnable target, AccessControlContext acc) {
        init(null, target, "Thread-" + nextThreadNum(), 0, acc, false);
    }
    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }
    public Thread(String name) {
        init(null, null, name, 0);
    }
    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }
    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }
    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }
    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }

2.2 init

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

    /*
     * InheritableThreadLocal values pertaining to this thread. This map is
     * maintained by the InheritableThreadLocal class.
     */
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
		/*** 为了强调本文描述重点,此处省略部分代码 ***/
        if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

        /* Set thread ID */
        tid = nextThreadID();
    }

结合上述代码,当一个线程创建后,成员变量threadLocals为空,成员变量inheritableThreadLocals则根据是否继承父线程inheritableThreadLocals判断逻辑初始化。

3. ThreadLocal

ThreadLocalMap类是ThreadLocal类的内部静态类。分析完ThreadLocalMap源码后,再分析ThreadLocal源码,就简单许多了。

3.1 set

set方法的作用是将传参设置到当前线程的成员变量threadLocals中。如果成员变量threadLocals为空,则调用creaeMap方法新建。

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

3.2 get

get方法从当前线程的成员变量threadLocals中获取当前ThreadLocal作为Key对应Entry的Value,如果threadLocals为空,或未找到,则返回初始值(可重写,默认为空)。

    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();
    }
    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);
        return value;
    }
    protected T initialValue() {
        return null;
    }

3.3 remove

从当前线程成员变量threadLocals中删除当前ThreadLocal作为Key对应Entry。

     public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

4. InheritableThreadLocal

public class InheritableThreadLocal<T> extends ThreadLocal<T> {
 
    protected T childValue(T parentValue) {
        return parentValue;
    }

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

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

InheritableThreadLocal类继承ThreadLocal类。需要强调的是,childValue方法用于继承父线程inheritableThreadLocals时,以什么形式复制其中的值,默认为直接返回父线程inheritableThreadLocals中Entry的Value值。

5. 总结

结合以上分析,ThreadLocal和InheritableThreadLocal主要用于变量在线程间共享,并不能解决线程安全问题,原因是其变量共享方式为潜拷贝。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值