【图解】ThreadLocal底层实现原理

1、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;
            }
        }

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值