美文网首页
ThreadLocal介绍

ThreadLocal介绍

作者: 一直在路上_求名 | 来源:发表于2020-06-23 01:13 被阅读0次

    ThreadLocal 能做什么

    ThreadLocal 是 JDK 提供的一个工具类,它可以为每个使用它的线程创建一个线程本地的副本,从而能保证多个线程在访问时的安全问题。当多个线程在使用这个变量时,其实是在使用自己线程本地内存的变量,由于是线程级别的,因此就能完全避免多个线程访问时,资源竞争的安全问题。

    ThreadLocal 的原理

    要讲解 ThreadLocal 的原理,我们首先需要看 JDK 的源码,了解了 ThreadLocal 类的主要方法实现就能理解其原理了。使用 ThreadLocal 时主要就是调用它的两个方法即 get 方法和 set 方法,下面直接贴出他们的源码。

    首先看 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);
        }
    
    ThreadLocalMap getMap(Thread t) {
            return t.threadLocals;
        }
    
    void createMap(Thread t, T firstValue) {
            t.threadLocals = new ThreadLocalMap(this, firstValue);
        }
    

    由于 ThreadLocal 是一个带泛型的类,所以在创建 ThreadLocal 对象时,需要指定对应的泛型而 set 方法的入参就是定义的泛型对象;
    接下来看具体的逻辑:
    1首先创建了一个当前调用 set 方法的线程实例对象;
    2、调用 getMap 方法,入参为当前线程的实例对象,返回一个当前线程对象的 threadLocals 属性值,threadLocals 是Thread 类的一个属性,也就是说 Java 的所有线程对象都有这个属性,这个属性是一个 ThreadLocalMap 对象(ThreadLocalMap 其实就是一个简化版的 HashMap);
    3、如果返回的 ThreadLocalMap 为 null(threadLocals 属性的默认值就是 null),则会创建一个 ThreadLocalMap 对象,会调用createMap 方法;
    4、createMap 方法接收两个入参,一个为 当前调用线程的实例对象,一个为 firstValue(默认 firstValue 为 null)因此这个方法会创建一个 key 为当前调用线程实例,value 为当前 set 方法传入的值 的ThreadLocalMap 对象,并将这个对象赋值给当前线程实例的 threadLocals 属性;
    总结:要想了解 set 方法,就需要了解 threadLocals 属性,简单理解它就是一个 key 为当前线程实例对象的 HashMap;set 方法就是把 set 的入参设置到这个 hashMap 的 value 中的过程;

    接下来看 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();
        }
    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;
        }
    

    其实 get 方法和 set 方法一样,本质上都是操作当前线程实例的 threadLocals 属性,只是 get 方法是获取该属性的 value 值;
    接下来看具体的逻辑:
    1、前面的两个操作和 set 方法一样,获取当前调用线程实例的 threadLocals 属性值;
    2、如果不为空则直接返回当前属性值的 value 值;
    3、如果为空则为当前线程实例初始化一个 value 值为空的 threadLocals 属性(initialValue 方法的返回值为 null);

    原理总结

    1、通过以上源码介绍,其实 ThreadLocal 是一个带泛型的类,使用的时候就是调用它的 get 方法和它的 set 方法;
    2、这两个方法的本质就是操作当前调用线程实例的 threadLocals 属性值;
    3、threadLocals 属性是一个 Thread LocalMap 对象,这个对象就是一个简单的 HashMap,而它的 key 为当前线程的实例对象,value 为某个需要被共享的变量值;
    4、由于这个值是放在当前线程实例的一个 Map 中,因此多个线程访问的时候是访问自己本地的变量,因此不可能有多线程安全访问的问题;

    ThreadLocal 应用 Demo

    先上代码

    public static void main(String[] args) {
            ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
            stringThreadLocal.set("main threadLocal");
            System.out.println("main threadLocal value:"+stringThreadLocal.get());
            Thread threadA = new Thread(() -> {
                stringThreadLocal.set("threadA threadLocal");
                System.out.println("threadA threadLocal value:" + stringThreadLocal.get());
            });
            Thread threadB = new Thread(() -> {
                stringThreadLocal.set("threadB threadLocal");
                System.out.println("threadB threadLocal value:" + stringThreadLocal.get());
            });
            threadA.start();
            threadB.start();
        }
    

    结果

    main threadLocal value:main threadLocal
    threadA threadLocal value:threadA threadLocal
    threadB threadLocal value:threadB threadLocal
    

    上面是对 ThreadLocal 最简单的使用,虽然对 ThreadLocal 来说是一个对象,并且是被三个线程共同访问,正常情况下由于多线程的问题一定会表现为结果不可预知;但是由于 ThreadLocal 的特性,是当前线程的本地副本设置属性值,因此不会出现多线程安全的问题;可以用它来记录一下上下文的一内容信息,或者用来设置一个日志的唯一标识 uuid 等,来标识当前线程的执行日志,方便查找问题。

    相关文章

      网友评论

          本文标题:ThreadLocal介绍

          本文链接:https://www.haomeiwen.com/subject/mlvdxktx.html