Java 线程隔离ThreadLocal

作者: OnlyPiglet | 来源:发表于2020-02-26 20:34 被阅读0次

有关Java线程隔离方面的问题也是面试中必问的一个问题,今天就好好看一下ThreadLocal 实现原理,也是我们在解决多线程数据安全时比较常用的一个手段

实现理论

将变量保存为每个线程栈内部的变量,因为线程栈与线程栈之间内部的变量不不会相互影响的,所以就不会存在数据不安全的情况。

代码实现

Thread类

ThreadLocal.ThreadLocalMap threadLocals = null;

Thread内由此Map 负责维护 Thread 内被隔离的变量

ThreadLocalMap

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

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

此Map中的key为 ThreadLocal对象,value为存在Thread被隔离变量的值。

ThreadLocal

当使用ThreadLocal set值的时候

    public void set(T value) {
        //获取当前操作线程对象
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            //将值 放置在 当前线程局部变量 ThreadLocalMap 中
            map.set(this, value);
        else
            createMap(t, value);
    }
    ThreadLocalMap getMap(Thread t) {
        //获取当前线程局部变量 ThreadLocalMap 
        return t.threadLocals;
    }

至此可以发现达到了 线程隔离的效果

当使用 ThreadLocal get值的时候

    public T get() {
        //获取当前线程对象
        Thread t = Thread.currentThread();
        //获取当前线程局部变量 ThreadLocalMap 
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            //从Map中 根据 threadlocal key及this 获取value
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

小结

至此大概可以总结出Thread ThreadLocal ThreadLocalMap 之间的关系

Thread 中存在 ThreadLocalMap 的强引用,ThreadLocalMap 中 Entry 存在 key 为 ThreadLocal 的弱引用,以及任意类型 value 的强引用

此处就会出现 内存泄漏 的情况,当一次GC过后,ThreadLocal 会被回收掉变为null,所以ThreadLocalMap 中的key变为null,此时value理应被回收掉,但是如果线程对象没有结束的话,就会存在 Thread -> ThreadLocalMap -> Entry -> (null,value) 的引用链,导致value不会被回收,为了应对这种情况的发生,ThreadLocal 在get 和 set 操作时会将key为null的 Entry 的 value 也变为 null

  private int expungeStaleEntry(int staleSlot) {
            Entry[] tab = table;
            int len = tab.length;

            // expunge entry at staleSlot
            tab[staleSlot].value = null;
            tab[staleSlot] = null;
            size--;

            // Rehash until we encounter null
            Entry e;
            int i;
            for (i = nextIndex(staleSlot, len);
                 (e = tab[i]) != null;
                 i = nextIndex(i, len)) {
                //如果key为null,则将对应的value也变为null,同时将长度减一
                ThreadLocal<?> k = e.get();
                if (k == null) {
                    e.value = null;
                    tab[i] = null;
                    size--;
                } else {
             //省略部分代码
                }
            }
            return i;
        }

总结

  1. Thread -> ThreadLocal.ThreadLocalMap -> Entry -> (weakReferencr<ThreadLocal>,T value)
  2. 在 ThreadLocalMap set ,get 时 会执行 key为null 的 Entry 的 value 也变为null ,同时减少Map长度。

相关文章

  • ThreadLocal及其扩展

    ThreadLocal ThreadLocal是线程本地变量,每个线程往这个ThreadLocal中读写是线程隔离...

  • Java 线程隔离ThreadLocal

    有关Java线程隔离方面的问题也是面试中必问的一个问题,今天就好好看一下ThreadLocal 实现原理,也是我们...

  • Java 之 ThreadLocal 详解

    ThreadLocal 在java中是充当“线程本地变量”使用的,在每个线程都会创建该对象从而实现线程之间的隔离,...

  • ThreadLocal

    ThreadLocal threadlocal 线程变量,每个线程都有单独的变量。用于线程之间的隔离。 Threa...

  • JDK ThreadLocal解析

    Java ThreadLocal解析 ThreadLocal 线程本地变量, 线程私有, 在 Thread 类中用...

  • 多线程之ThreadLocal

    ThreadLocal threadLocal是用来解决多线程并发访问的线程安全问题,其实就是把变量隔离在线程内部...

  • 多线程-ThreadLocal

    ThreadLocal by shihang.mai 线程隔离 类ThreadLocal的set(),调用的get...

  • ThreadLocal

    1. ThreadLocal定义 ThreadLocal是线程变量,用于填充当前线程的变量,该变量与其他线程是隔离...

  • ThreadLocal剖析

    ThreadLocal可以在多线程下实现各个线程的数据隔离 存储原理 直接看ThreadLocal的get()方法...

  • ThreadLocal 解析

    ThreadLocal 每个线程都有一个 ThreadLocal 变量的副本,实现了线程的隔离。 使用 实现 ru...

网友评论

    本文标题:Java 线程隔离ThreadLocal

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