美文网首页
深入ThreadLocal

深入ThreadLocal

作者: 丁木木木木木 | 来源:发表于2017-03-24 12:38 被阅读27次

主要内容

  • ThreadLocal
  • 基本操作
  • 实现原理

前言

本文主要深入了解ThreadLocal的内部实现原理,实习项目用到过ThreadLocal,因此了解它的原理以及运用场景还是很有用的。ThreadLocal顾名思义是线程本地,它指的是为维护的变量在每一个线程内创建副本,每个线程可以独立访问使用自己的变量副本,线程之间相互不干扰。
总结起来,其实ThreadLocal提供了线程的局部变量,在多线程环境下这些变量能独立于其他线程内的变量,一般ThreadLocal都是private static类型的,用于关联线程上下文。

基本操作

先来看看ThreadLocal的基本操作。

构造函数

    public ThreadLocal() {
    }

发现构造方法里啥也没做。接下来看其他方法。

设值方法

    /**
     * initialValue方法会在第一次调用get方法时被调用,但是如果刚开始就调用了set方法,这个函数就不会调用。一般初始化方法只会调用一次,除非手动调用remove方法后又调用了get函数
     * @return the initial value for this thread-local返回threadLocal的初始值
     */
    protected T initialValue() {
        return null;
    }

一般建议使用匿名内部类重写这个方法,来指定初始值,例如:

    private static final ThreadLocal<Integer> value = new ThreadLocal<Integer>() {
        @Override
        protected Integer initialValue() {
            return Integer.valueOf(1);
        }
    };

深入

get方法源码

想知道ThreadLocal怎么实现之前,先来看看get源码

    public T get() {
        Thread t = Thread.currentThread();//获取当前线程
        ThreadLocalMap map = getMap(t);//根据当前线程获取到ThreadLocalMap
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);//当前ThreadLocal的引用作为key
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;//由线程类的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;
    }
    
    void createMap(Thread t, T firstValue) {//创建新的ThreadLocalMap
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

流程主要是:
1.先获取当前线程
2.然后调用getMap方法根据当前线程获取到ThreadLocalMap,观察源码发现ThreadLocalMap是由线程类的threadLocals变量获取
3.如果获取到的map不为空的话,则将当前ThreadLocal的引用作为key,返回ThreadLocalMap的节点Entry类
4.如果节点不为null的话,直接返回对应的value 值
5.如果map为空或获取到的节点为null,调用setInitialValue设值初始值

实现原理

让大家来思考下如果是你的话你会怎么实现,我首先想到的是为ThreadLocal类创建一个维护ThreadLocalMap的映射表,然后由Thread的ID值作为key值,value值存储实例对象。
来看看JDK中ThreadLocal的实现原理

    ThreadLocal.ThreadLocalMap threadLocals = null;

Thread类中维护一个变量表示ThreadLocalMap映射表,key值为当前ThreadLocal的引用,value值为真正需要存储的对象。

我们会发现,用ThreadLocal作为key值,比用Thread线程ID作为key,创建的Entry数量减少得多;而且生命周期和Thread相同,如果线程被销毁,对应的ThreadLocalMap也被销毁了。

ThreadLocalMap

ThreadLocalMap内部类里主要使用ThreadLocal的弱引用作为键key,如果ThreadLocal为null的话会删除对应的Entry。

    static class Entry extends WeakReference<ThreadLocal> {
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal k, Object v) {
                super(k);
                value = v;
            }
    }

相关文章

网友评论

      本文标题:深入ThreadLocal

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