ThreadLocal详细讲解(适合新手)

ThreadLocal详细讲解(小白都能看懂)

一、ThreadLocal的作用:

我初始化一个ThreadLocal变量target,初始值即为null;

在进程1里,我将它设为1;

在进程2里,我获取这个初始值,他还是null,同时我将它设成3;

在进程3里,我获取它,还是null。

各个进程对于这个变量的操作都是独立的。

ThreadLocal详细讲解(适合新手)_第1张图片

二、ThreadLocal源代码讲解

1.创建ThreadLocal对象。

ThreadLocal<Integer> target = new ThreadLocal<>(); //设置ThreadLocal变量target
target.get();  //获取target值
target.set(1); //设置target值

2.ThreadLocal.get()

其中t.get()是ThreadLocal.get()方法

public T get() {
     
        Thread t = Thread.currentThread();  //得到当前线程
        ThreadLocalMap map = getMap(t);    //获取当前线程的ThreadLocalMap
        if (map != null) {
     
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
     
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

3.ThreadLocal.getMap()

那么得到的这个map是什么东西? 我们来看看ThreadLocal.getMap()源码

ThreadLocalMap getMap(Thread t) {
      //Thread t代表的是当前线程
        return t.threadLocals; //原来,每个线程有个threadLocals,它是ThreadLocalMap类型的变量
    }

在Thread.java中,会对这个threadLocals进行初始化

ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

4.ThreadLocal.set()

接下来我们需要知道ThreadLocalMap这个类型放了啥,我们通过ThreadLocal.set()来看,从它的源码我们发现其实他是调用了ThreadLocalMap.set()实现的

    public void set(T value) {
     
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value); //其实ThreadLocal.set()是通过ThreadLocalMap.set()实现的
                              //map.set有两个参数,一个是ThreadLocal(也就是一开始我的target对象),一个是value
        else
            createMap(t, value);
    }

5.ThreadLocalMap.set()

为了大家看的更清楚,我附上ThreadLocalMap.set() 的源码,随意看看就好,主要是看清楚传进去的ThreadLocal和value

private void set(ThreadLocal<?> key, Object value) {
     

            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);

            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
     
                ThreadLocal<?> k = e.get();

                if (k == key) {
     
                    e.value = value;
                    return;
                }

                if (k == null) {
     
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

内存泄漏

ThreadLocalMap中使用的key为ThreadLocal的弱引用,value为强引用。当ThreadLocal没被外部引用时key会被GC回收,导致key为null,而value永远无法被回收从而内存泄漏。最好每次用完ThreadLocal后手动调用remove()。

总结

最后结合我画的图,应该很清晰明了了,对于更加深层的原理我后续还会补充。同时推荐一个小白都能看得懂的讲解,很清晰透彻。

你可能感兴趣的:(JAVA基础,多线程,java,多线程)