江西省住房城乡建设厅网站阴阳师网站怎么做
2026/5/20 19:18:55 网站建设 项目流程
江西省住房城乡建设厅网站,阴阳师网站怎么做,黄岩区建设局网站,做网站服务器配置应该怎么选Java 中 ThreadLocal.ThreadLocalMap 是 ThreadLocal 机制内部用来存储每个线程私有变量的数据结构。下面我将从 整体设计、哈希冲突处理、内存泄漏防护、以及流程模拟 四个方面进行详细解析#xff0c;并在最后给出一张 内存结构图 和 一次 get/set 流程示例。一、整体设计思…Java 中ThreadLocal.ThreadLocalMap是ThreadLocal机制内部用来存储每个线程私有变量的数据结构。下面我将从整体设计、哈希冲突处理、内存泄漏防护、以及流程模拟四个方面进行详细解析并在最后给出一张内存结构图和一次 get/set 流程示例。一、整体设计思想1.1 ThreadLocalMap 是什么它是一个定制化的哈希表hash map只用于保存当前线程的ThreadLocal变量。不对外暴露任何操作接口包私有仅由ThreadLocal类使用。每个Thread对象内部持有一个ThreadLocalMap实例字段名为threadLocals。1.2 Entry 结构staticclassEntryextendsWeakReferenceThreadLocal?{Objectvalue;}Key 是ThreadLocal对象本身但被包装成弱引用WeakReference。Value 是用户存入的实际数据。当某个ThreadLocal对象没有强引用指向它时即用户不再持有该ThreadLocal实例GC 会回收 key此时 entry 的 key 变为null称为stale entry陈旧条目。⚠️ 注意由于 key 是弱引用value 不会被自动回收若不清理 stale entry会导致内存泄漏。二、如何解决哈希冲突2.1 哈希函数intikey.threadLocalHashCode(table.length-1);使用ThreadLocal自带的threadLocalHashCode一个固定、均匀分布的 long 值。表长度始终是2 的幂所以用 (len - 1)等价于取模效率高。2.2 冲突解决策略线性探测Linear Probing当目标槽位已被占用无论是否 stale就顺序向后查找下一个空槽privatestaticintnextIndex(inti,intlen){return((i1len)?i1:0);// 循环回到开头}这是一种开放寻址法Open Addressing不是链表或红黑树。✅ 优点缓存友好局部性好❌ 缺点容易聚集clustering需配合清理 stale entry三、内存泄漏防护机制3.1 为什么会有内存泄漏Key 是弱引用 → GC 后 key null但 Entry 本身还在 table 中 → value 仍被强引用 → 无法回收3.2 如何清理 stale entry1expungeStaleEntry(int staleSlot)从staleSlot开始向后扫描直到遇到 null 槽删除所有 key null 的 entry对非 stale entry重新 rehash 插入因为线性探测依赖连续性2cleanSomeSlots(int i, int n)启发式扫描对数级别log n地检查部分槽位在set()成功插入新元素后调用平衡性能与清理效果3replaceStaleEntry(...)在set()时如果遇到 stale entry不仅替换还顺带清理整个“run”连续非空段4rehash()先全表清理 stale entries若 size 仍 ≥ 3/4 * threshold则 resize扩容为 2 倍 关键点不使用 ReferenceQueue所以 stale entry不会自动通知只能靠主动探测清理。四、get / set 流程详解附模拟场景设定初始ThreadLocalMap容量 16存入两个ThreadLocaltl1,tl2假设tl1.threadLocalHashCode 15 3tl2.threadLocalHashCode 15 3→哈希冲突✅ set(tl1, “A”) 流程计算索引i 3table[3] null→ 直接放入new Entry(tl1, A)size 1调用cleanSomeSlots(3, 1)→ 扫描约 log₂(1)0 次基本不扫结束index: 0 1 2 [3] 4 ... 15 . . . [tl1→A] ...✅ set(tl2, “B”) 流程冲突发生计算索引i 3table[3] ! null且e.get() tl1 ≠ tl2进入 for 循环i nextIndex(3,16) 4table[4] null→ 退出循环table[4] new Entry(tl2, B)size 2调用cleanSomeSlots(4, 2)→ 扫描 log₂(2)1 次检查 index 5若无 stale结束index: 0 1 2 [3] [4] 5 ... . . . [tl1→A] [tl2→B] ...✅ get(tl2) 流程计算索引i 3table[3] ! null但e.get() tl1 ≠ tl2→miss调用getEntryAfterMiss(tl2, 3, table[3])进入 while 循环i3: ktl1 ≠ tl2 → i4i4: e ! null, ktl2 key →return e返回B❌ 内存泄漏场景未 remove假设之后tl2 null;用户丢弃引用GC 后table[4].get() null→ stale entry若长期不调用set/get/remove该 entry 不会被清理 →B一直占用内存✅ 正确做法使用完 ThreadLocal 后调用tl.remove()五、ThreadLocal 内存结构图--------------------- | Thread | | | | threadLocals ─────┼───► ThreadLocalMap | | ------------------ --------------------- | table (Entry[]) | | [0] | | [1] | | ... | | [3] ──► Entry ──► { key: WeakRef(tl1), value: A } | [4] ──► Entry ──► { key: WeakRef(tl2), value: B } | ... | ------------------ Entry 继承 WeakReferenceThreadLocal └── key 通过 get() 获取可能为 null └── value 是强引用需手动清理 每个线程有自己的ThreadLocalMap互不干扰 →线程隔离六、总结关键点特性说明哈希冲突线性探测开放寻址Key 引用类型WeakReference防 ThreadLocal 本身泄漏Value 生命周期依赖 stale entry 清理否则内存泄漏清理时机get/set/remove 时触发 expunge/cleanSomeSlots/rehash扩容条件size ≥ 2/3 * capacity且清理后仍 ≥ 3/4 * threshold最佳实践使用完务必remove()如有需要我可以进一步画出ASCII 流程图或UML 结构图。希望这份详解能帮你彻底理解ThreadLocalMap的精妙设计

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询