ThreadLocal学习

    xiaoxiao2022-06-26  218

    前言

    基于引用的学习,来简单的看一下ThreadLocal的实现。ThreadLocal简单来时是线程本地变量,解决共享对象(单个线程内共享)的多线程访问问题的,其不同于synchonized的关键点在于,synchronized是利用锁机制,保证共享对象在某一时刻只能被一个线程访问,但是ThreadLocal是为每个线程提供变量副本。其劣势在于为每个线程并发访问的数据建立了一个副本,会造成内存消耗。 常见的坑:没有进行remove操作,会造成内存泄露问题。(注意并不是ThreadLocal出现的地方就得调用remove,如果ThreadLocal是静态变量等情况,其生命周期和程序一样长,就不是很必要了)

    内存泄露原因分析

    ThreadLocalMap

    static class ThreadLocalMap { // 继承自弱引用意味着在发生gc时,如果key值ThreadLocal被发现只有一个弱引用,其会被回收,此时如果发现创建ThreadLocal的线程一直在运行的话,那么Entry对象的value值将一直得不到回收,发生内存泄漏。 static class Entry extends WeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */ Object value; /** * public WeakReference(T referent) { * super(referent); * } */ Entry(ThreadLocal k, Object v) { super(k); value = v; } } ... // 由set方法中createMap调用 ThreadLocalMap(ThreadLocal firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); } ... // 由map方法中map.getEntry(this)调用 private Entry getEntry(ThreadLocal key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else // 此过程中会清理key值为空的Entry对象 return getEntryAfterMiss(key, i, e); } }

    set方法

    public void set(T value) { // t为正在执行的当先线程的句柄 Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) // 此过程也会清理key值为空的Entry对象 map.set(this, value); else createMap(t, value); } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } /** * ThreadLocal.ThreadLocalMap threadLocals = null; */ ThreadLocalMap getMap(Thread t) { return t.threadLocals; }

    get方法

    public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }

    简单示例

    public class ThreadLocalTest { public static void main(String[] args) { ThreadLocal<String> localName = new ThreadLocal<>(); try { localName.set("Hello World"); String name = localName.get(); System.out.println(name); } finally { // 此处请注意 localName.remove(); } } }

    最新回复(0)