首页 > 编程语言 >浅析ThreadLocal源码

浅析ThreadLocal源码

时间:2024-02-24 09:03:41浏览次数:23  
标签:key int 位置 len ThreadLocal 源码 tab null 浅析

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[] 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();

        // 1.找空闲位置的过程中查看这个key是不是已经存在,存在 覆盖其value 结束
        if (k == key) {
            e.value = value;
            return;
        }
        // 2.找空闲位置的过程中遇到key已经被GC的话,替换掉这个entry 然后结束
        if (k == null) {
            replaceStaleEntry(key, value, i);
            return;
        }
    }

    // 执行到这个位置,说明:i是空位置且从最开始的下标i当前的下标i,这之间没有相同的key,也没有被GC的key
    tab[i] = new Entry(key, value);
    int sz = ++size;
    // i是当前插入的下标
    // cleanSomeSlots 是试探性的从i位置开始扫描过期被GC的key,扫描的元素个数是log2(sz)次
    // rehash的条件是试探性扫描没有扫描出来需要回收的entry且元素个数已经达到阈值
    if (!cleanSomeSlots(i /*当前插入的位置*/, sz /*当前一共有多少元素*/) && sz >= threshold)
        rehash();
}
private boolean cleanSomeSlots(int i, int n) {
    boolean removed = false;
    Entry[] tab = table;
    int len = tab.length;
    // 循环执行log2(n)次
    do {
        i = nextIndex(i, len);
        Entry e = tab[i];
        // 如果当前位置的 Entry 对象不为空且其关联的键为 null(即已过期),则执行下面的操作
        if (e != null && e.get() == null) { 
            n = len;
            removed = true;
            i = expungeStaleEntry(i);
        }
    } while ( (n >>>= 1) != 0);
    return removed;
}
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;
    // 使用循环从下一个槽位开始,遍历直到遇到 null 条目。这个循环主要用于重新哈希(ThreadLocalMap 使用的是 线性探测解决哈希冲突 )。
    for (i = nextIndex(staleSlot, len);
         (e = tab[i]) != null;
         i = nextIndex(i, len)) { 
        ThreadLocal<?> k = e.get();
        if (k == null) {
            // 检查ThreadLocal是否为null  如果为null需要移除
            e.value = null;
            tab[i] = null;
            size--;
        } else /* key!=null */ {
            int h = k.threadLocalHashCode & (len - 1);
            if (h != i) {   // ThreadLocalMap 使用的是 线性探测解决哈希冲突 因此是有可能 h!=i的
                tab[i] = null;

                // Unlike Knuth 6.4 Algorithm R, we must scan until
                // null because multiple entries could have been stale.
                // 说明之前出现冲突 将原来i位置的搬到h位置
                while (tab[h] != null/*h位置已经有元素了,说明现在任然冲突,将其放到h后面第一个空位置*/)
                    h = nextIndex(h, len);
                tab[h] = e;
            }
        }
    }
    return i;
}

对于expungeStaleEntry,参考下图:

如图,staleSlot位置需要清掉,后面的元素需要重新哈希,直到遇到entry还是null的为止,也就是会遍历到staleSlot+3位置会停下来,对i位置重新哈希计算的位置h已经存在元素,从h往后遍历,遇到空位置就将i位置的entry移过去。

标签:key,int,位置,len,ThreadLocal,源码,tab,null,浅析
From: https://www.cnblogs.com/d9e84208/p/18030701

相关文章

  • APIview源码分析
    1APIview的as_view -内部还是执行了View的闭包函数view-禁用掉了csrf-一切皆对象,函数也是对象函数地址.name=lqz2原生View类中过的as_view中的闭包函数view -本质执行了self.dispatch(request,*args,**kwargs),执行的是APIView的dispatch3APIView的dispatchdef......
  • ThreadLocal
    前置知识Java中有些引用类型?Java中主要有4种引用类型,分别是:强、软、弱、虚。他们主要跟Java的垃圾回收机制有关强引用:Java中默认的引用类型,一个对象如果具有强引用,那么只要这种引用还存在就不会被回收软引用:在内存充足时,是不会GC这个对象的。只有在JVM内存不足的时候才会调用......
  • Kubernetes leader election 源码分析
    0.前言Kubernetes:kube-scheduler源码分析介绍了kube-scheduler调度Pod的逻辑。文中有一点未提的是,在Kubernetes集群中,kube-scheduler组件是多副本,单实例运行。仅有一个副本作为leader运行,当发生故障时,其它副本会抢占为leader继续运行。这种机制通过leaderelect......
  • 多线程系列(七) -ThreadLocal 用法及内存泄露分析
    一、简介在Javaweb项目中,想必很多的同学对ThreadLocal这个类并不陌生,它最常用的应用场景就是用来做对象的跨层传递,避免多次传递,打破层次之间的约束。比如下面这个HttpServletRequest参数传递的简单例子!publicclassRequestLocal{/***线程本地变量*/......
  • shiro 整合 spring 实战及源码详解
    序言前面我们学习了如下内容:5分钟入门shiro安全框架实战笔记shiro整合spring实战及源码详解相信大家对于shiro已经有了最基本的认识,这一节我们一起来学习写如何将shiro与spring进行整合。spring整合maven依赖<dependencies><dependency><group......
  • stl源码解析,deque的insert_aux
    直接上结论:deque的insert_aux中插入开始会pushback或front一个和最末尾或最前面值相同的值是为了看是否需要扩充deque内存,选这个值应该是顺手。stl中deque的实现是通过一个存储指向各个存储区域指针的map(注意就是个指针地图,不是stl的map数据结构),里面再指向对应区域去存储实际......
  • 设计模式浅析(六) ·命令模式
    设计模式浅析(六)·命令模式日常叨逼叨java设计模式浅析,如果觉得对你有帮助,记得一键三连,谢谢各位观众老爷......
  • home-assistant core 源码粗读--对设备历史的处理(三)
    我们已经知道User等保存是直接以json的形式直接保存到文件中。先说结论:设备的检测历史默认保存在sqlite中Thedefault,andrecommended,databaseengineis SQLite whichdoesnotrequireanyconfiguration.ThedatabaseisstoredinyourHomeAssistantconfigurati......
  • (附项目源码)uni-app关于uni-ui使用问题
    uni-app关于uni-ui使用问题:https://blog.csdn.net/linan996/article/details/121503372?ops_request_misc=&request_id=&biz_id=102&utm_term=uniapp%20%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%20uni_modules&utm_medium=distribute.pc_search_result.none-task-blo......
  • Java人力资源管理系统源码(含数据库)-springboot+vue+mysql
    EHR人力资源管理系统是一种利用现代技术,如云计算、大数据等,来实现企业人力资源信息电子化、流程自动化的系统。它覆盖了人力资源管理的各个方面,从招聘、考勤、绩效到薪酬、社保公积金等,为企业提供一站式的解决方案。​1.招聘管理:-职位发布:系统支持在线发布职位信息,吸引候选人......