欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

ThreadLocal中的一些点

程序员文章站 2022-03-26 15:47:04
ThreadLocalMap是ThreadLocal中的一个静态内部类ThreadLocalMap中有一个Entry数组,存放着value可能导致内存泄漏因为,ThreadLocalMap中的Entry中的key也就是传进来的ThreadLocal是弱引用,也就说ThreadLocal对象分别有一个强引用一个弱引用,如果ThreadLcoal的强引用失去后,只剩下弱引用,n那就在下次垃圾回收时key就会被回收,value不会被回收,就会导致Entry数组的某一位,e.get() == nulle.v....

ThreadLocalMap是ThreadLocal中的一个静态内部类
ThreadLocalMap中有一个Entry数组,存放着value

内存泄漏

ThreadLocal中的一些点

可能导致内存泄漏因为,ThreadLocalMap中的Entry中的key也就是传进来的ThreadLocal是弱引用,也就说ThreadLocal对象分别有一个强引用一个弱引用,如果ThreadLcoal的强引用失去后,只剩下弱引用,n那就在下次垃圾回收时key就会被回收,value不会被回收,就会导致Entry数组的某一位,e.get() == null
e.value != null ,导致内存泄漏。
ThreadLocalMap本身有一些预防措施,在set和get的时候会清除那些内存泄漏的地方
我们正确使用时,在用完ThreadLocal的时候remove一下,就行了

ThreadLocal 主要是用他的hashcode做key

这个hash数字找的太精彩了,每次求新的hash码只需要累加就行了,最后取模的时候就会很分散!!!!

ThreadLocal中的一些点
有同学注意到,这样不会爆int吗?答案:会 正是因为会爆int所以均匀,即使爆了int,数也不是随机来的,重新从负数开始
ThreadLocal中的一些点
网上一个测试。
ThreadLocal中的一些点
每个线程都有一个ThreadLocalMap 的实例对象 这个对象是以 threadLocalHashCode作为key,value作为值的,一个线程可以有很多ThreadLocal;

分析一下set过程

ThreadLocal中的set

    public void set(T value) {
        Thread t = Thread.currentThread();//得到现在是哪个线程
        ThreadLocalMap map = getMap(t);//得到该线程的ThreadLocalMap实例
        if (map != null) { //如果不是第一次初始化
            map.set(this, value);//调用ThreadLocalMap中的HashMap
        } else { //如果是第一次初始化
            createMap(t, value);
        }
    }

ThreadLocalMap中的set

  private void set(ThreadLocal<?> key, Object value) { 
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);//获得在table中的位置
			//冲突顺延法
            for (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
				//如果以前存在就更新
                if (k == key) {
                    e.value = value;
                    return;
                }
				//找到空位就new
                if (k == null) {
                //replaceStaleEntry间接调用-整理那些内存泄漏的位置
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }

            tab[i] = new Entry(key, value);
            int sz = ++size;
            //整理那些内存泄漏的位置
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }
        //整理那些内存泄漏的位置
      private boolean cleanSomeSlots(int i, int n) {
            boolean removed = false;
            Entry[] tab = table;
            int len = tab.length;
            do {
                i = nextIndex(i, len);
                Entry e = tab[i];
                if (e != null && e.get() == null) {
                    n = len;
                    removed = true;
                    i = expungeStaleEntry(i);
                }
            } while ( (n >>>= 1) != 0);
            return removed;
        }

分析一下get

   public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
        //调用ThreadLocalMap的getEctry
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
	//通过hash定位,看看是不是null,不是null看看是不是当前ThreadLocal,如果不是顺序后延查找
    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
             //getEntryAfterMiss间接调用-整理那些内存泄漏的位置
                return getEntryAfterMiss(key, i, e);
        }

本文地址:https://blog.csdn.net/weixin_43912833/article/details/113926727

相关标签: JVM 后端