ThreadLocal详解

ThreadLocal详解,第1张

ThreadLocal详解 一、代码使用示例
public class ThreadLocalDemo {
    static ThreadLocal localVar = new ThreadLocal<>();

    static void print(String str) {
        //打印--当前线程--中本地内存中本地变量的值
        System.out.println(str + localVar.get());
        //清除本地内存中的--当前线程--本地变量
        localVar.remove();
    }

    public static void main(String[] args) {
        Thread t1  = new Thread(new Runnable() {
            @Override
            public void run() {
                //设置线程1中本地变量的值
                localVar.set("线程1");
                int a = 1;
                //调用打印方法
                print("thread t1: ");
                //打印本地变量 print里面已经remove
                System.out.println("删除后 : " + localVar.get());
            }
        });

        Thread t2  = new Thread(new Runnable() {
            @Override
            public void run() {
                //设置线程1中本地变量的值
                localVar.set("线程2");
                //调用打印方法
                print("thread t2: ");
                //打印本地变量 print里面已经remove
                System.out.println("删除后 : " + localVar.get());
            }
        });

        t1.start();
        t2.start();
    }
}
二、ThreadLocal源码分析

ThreadLocal的set方法,实际是往实际调用的当前线程Thread的 ThreadLocalMap 类型的变量threadLocals里面 set key为 当前 ThreadLocal,value为当前set的值。
ThreadLocal源码分析:

public void set(T value) {
    //取当前实际调用的线程
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    //如果map不为null,开始set值,key为当前定义的ThreadLocal变量的this引用,值为添加的本地变量值
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
    
ThreadLocalMap getMap(Thread t) {
    //返回Thread类下的定义的 ThreadLocal.ThreadLocalMap threadLocals
    return t.threadLocals;
}

ThreadLocal类get方法,类似Map的方式,源码如下:

 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;
}
三、父子线程间变量传递问题

同一个ThreadLocal变量在父线程中被设置值后,在子线程中是获取不到的。因为threadLocals为当前调用线程对应的本地变量,所以二者是不能共享的。
那子线程如何访问父线程的本地变量呢,可以使用InheritableThreadLocal类。InheritableThreadLocal类继承了ThreadLocal类,并重写了childValue、getMap、createMap三个方法。
使用示例:

public class InheritableThreadLocalDemo {

    private static InheritableThreadLocal threadLocal = new InheritableThreadLocal<>();

    public static void main(String[] args) {
        threadLocal.set("主线程变量");
        System.out.println("value main:"+threadLocal.get());
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                String value = threadLocal.get();
                System.out.println("value child:"+value);
            }
        });
        thread.start();
    }

}

输出结果:
value main: 主线程变量
value child: 主线程变量

四、注意事项

ThreadLocalMap中的Entry的key使用的是ThreadLocal对象的弱引用,在没有其他地方对ThreadLocal依赖,ThreadLocalMap中的ThreadLocal对象就会被回收掉,但是对应的不会被回收,这个时候Map中就可能存在key为null但是value不为null的项,所以,在实际的时候使用完毕后要及时调用remove方法避免内存泄漏。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5573263.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-14
下一篇 2022-12-14

发表评论

登录后才能评论

评论列表(0条)

保存