ThreadLocal使用及原理赏析

ThreadLocal

ThreadLocal是JDK包提供的,它提供了线程本地变量,访问这个变量的每一个线程都会有这个变量的一个本地副本。当多线程操作这个变量时,实际上是操作自己本地内存里的变量。

1、使用示例

package io.juc;

public class Juc_11 {
    static void print(String str){
        System.out.println(str+":"+localVariable.get());
        localVariable.remove();
    }
    static ThreadLocal<String> localVariable=new ThreadLocal<>();

    public static void main(String[] args) {
        Thread threadOne =new Thread(new Runnable() {
            @Override
            public void run() {
                //设置的是线程one本地内存中的一个副本,所以线程two无法访问
                localVariable.set("threadOne local variable");
                print("threadOne");
                System.out.println("threadOne remove after:"+localVariable.get());
            }
        });
        Thread threadTwo=new Thread(new Runnable() {
            @Override
            public void run() {
                localVariable.set("threadTwo local variable");
                print("threadTwo");
                System.out.println("threadTwo remove after:"+localVariable.get());
            }
        });
        threadOne.start();
        threadTwo.start();
    }
}

2、实现原理

类图如下

在这里插入图片描述

源码分析

    public T get() {
        //获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程的threadLocals,见下一段代码
        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();
    }

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

    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;
    }

set方法

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            //没有就进行创建
            createMap(t, value);
    }

3、inheritableThreadLocals

子线程可以使用父线程的变量

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

    ThreadLocalMap getMap(Thread t) {
       return t.inheritableThreadLocals;
    }
	//inheritableThreadLocals代替了
    void createMap(Thread t, T firstValue) {
        t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
    }
}

//在构造Thread时,init,会先检查父线程的inheritableThreadLocals是否为null,如果不是的话,会将当前的inheritThreadLocals通过构造parent.inheritableThreadLocals构造
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        /* Stash the specified stack size in case the VM cares */
        this.stackSize = stackSize;

4、应用场景

那么在什么情况下需要 线程可以获取父线程的 threadlocal 变量呢?情况还是蛮多

的,比如子线程需要使用存放在 threadlocal 中的用户 登录信息,再比如一些中间件

要把统一的 id 个调用链路记录下来。其实子线程使用父线程中的 threadlocal

法有多种方式, 比如创建线程时传入父线程中的变量,并将其复制到子线程中,或者在父

线程中构造一个 map 作为参数传递给子线程,但是这些都改变了我们的使用习惯,所以

在这些情况下 Inheritab I e ThreadLocal 就显得比较有用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值