> 文档中心 > 【图解】ThreadLocal底层实现原理

【图解】ThreadLocal底层实现原理

1、ThreadLocal的底层原理图
【图解】ThreadLocal底层实现原理
说明:Thread中有threadLocals成员变量,threadLocal会在threadlocal首次set时进行赋值【这会在非main线程中复现,主线程启动即会进行赋值】,ThreadLocalMap是ThreadLocal的静态内部类,在set时,会将我们新建threadLocal引用地址作为key,以此封装成一个Entry<ThreadLocal,Object>对象,可以存在多个不同的threadlocal,如果set的引用地址相同,就会进行覆盖,此处key的类型ThreadLocal继承弱引用也是会造成内存泄露的主要原因,在下面源码中会对此段相关点分别说明。

2.源码解析

package com.adun.test_threadlocal;/** * @author ADun * @date 2022/4/27 11:14 */public class ThreadLocalTest {    public static final ThreadLocal<Integer> threadLocal = new ThreadLocal();    public static final ThreadLocal<Integer> threadLocal2 = new ThreadLocal();    public static void main(String[] args) { threadLocal.set(1234); Integer num1 = threadLocal.get(); System.out.println(num1); Integer num2 = threadLocal.get(); System.out.println(num2); threadLocal2.set(111); System.out.println(threadLocal2.get());//最后必须remove,避免内存泄露threadLocal.remove(); threadLocal2.remove();    }}

ThreadLocal中的set方法以及涉及到的相关方法

    public void set(T value) { Thread t = Thread.currentThread(); //获取当前线程的threadLocals ThreadLocalMap map = getMap(t); if (map != null)     map.set(this, value); else //如果获取不到当前线程的threadlocals成员变量,则新建并将value放入     createMap(t, value);    }
 /**  * 获取当前线程的threadlocals     * Get the map associated with a ThreadLocal. Overridden in     * InheritableThreadLocal.     *     * @param  t the current thread     * @return the map     */    ThreadLocalMap getMap(Thread t) { return t.threadLocals;    }/** * 创建ThreadLocalMap,并对当前线程的threadlocals进行赋值     * Create the map associated with a ThreadLocal. Overridden in     * InheritableThreadLocal.     *     * @param t the current thread     * @param firstValue value for the initial entry of the map     */    void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue);    }

ThreadLocal静态内部类ThreadLocalMap

/**  * 初始化ThreadLocalMap的构造器      * Construct a new map initially containing (firstKey, firstValue).      * ThreadLocalMaps are constructed lazily, so we only create      * one when we have at least one entry to put in it.      */     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);     }/**   * 玩当前线程的threadlocals对应的threadLocalMap中赋值   * 用户new的threadlocal的引用地址作为key,value作为value进行赋值构建Entry对象,如果已存在,则进行覆盖* Set the value associated with key.** @param key the thread local object* @param value the value to be set*/      private void set(ThreadLocal<?> key, Object value) {   // We don't use a fast path as with get() because it is at   // least as common to use set() to create new entries as   // it is to replace existing ones, in which case, a fast   // path would fail more often than not.      //Entry<ThreadLocal,Object>数组,存放多个threadlocal的数据   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内部类Entry

/**  * The entries in this hash map extend WeakReference, using  * its main ref field as the key (which is always a  * ThreadLocal object).  Note that null keys (i.e. entry.get()  * == null) mean that the key is no longer referenced, so the  * entry can be expunged from table.  Such entries are referred to  * as "stale entries" in the code that follows.  */ static class Entry extends WeakReference<ThreadLocal<?>> {     /** The value associated with this ThreadLocal. */     Object value;//Entry继承弱引用,弱引用的特点是在jvm进行gc扫描中直接进行回收//这种操作既有可能k的引用被回收,而v的值失去所有到达的引用,造成内存泄露,所以在最后必须remove     Entry(ThreadLocal<?> k, Object v) {  super(k);  value = v;     } }