当前位置: 首页 > news >正文

建设银行网站查开户行网站做301打不开

建设银行网站查开户行,网站做301打不开,济南网站优化排名,移动应用开发女生学难不难#x1f4dd; 前言#xff1a;为什么你需要了解 ThreadLocal#xff1f;在多线程并发编程中#xff0c;线程安全始终是一个绕不开的话题。我们常常需要为每个线程维护一份独立的上下文数据#xff0c;例如用户信息、事务 ID、日志追踪 ID 等。这些数据不能被多个线程共享 前言为什么你需要了解 ThreadLocal        在多线程并发编程中线程安全始终是一个绕不开的话题。我们常常需要为每个线程维护一份独立的上下文数据例如用户信息、事务 ID、日志追踪 ID 等。这些数据不能被多个线程共享否则会导致数据错乱或线程安全问题。        Java 提供了一个非常优雅的工具类 —— ThreadLocal它允许我们为每个线程绑定一个线程私有的变量副本从而实现线程隔离、避免共享带来的并发问题。        但其底层实现 ThreadLocalMap 的机制却并不简单涉及到弱引用、哈希冲突处理、内存泄漏、清理机制、扩容策略等多个核心知识点。先讲结论后解释因为我自己看javaguide的时候观感就是这里一坨那里一坨的对结论不是很清晰导致读者自己有一些理解看javaguide的时候又有一些理解对结论的记忆就不是很清晰但其底层实现 ThreadLocalMap 的机制却并不简单涉及到弱引用、哈希冲突处理、内存泄漏、清理机制、扩容策略等多个核心知识点。为了帮助你快速掌握重点我先总结 ThreadLocal 的核心结论如下ThreadLocal 的核心结论先说 ThreadLocal 的核心结论总结供你快速掌握重点 1. ThreadLocalMap 是 ThreadLocal 的静态内部类ThreadLocalMap 是 ThreadLocal 的 静态内部类。包私有无法通过外部直接访问只能通过 ThreadLocal.get()、set() 等方法间接访问。每个线程拥有自己的 ThreadLocalMap所有 ThreadLocal 实例在该线程中都会映射到这个唯一的 Map。2. ThreadLocalMap 中的 Key 是弱引用ThreadLocalMap 中的键值对结构为 Entry extends WeakReferenceThreadLocal?。Key 是 ThreadLocal 实例的弱引用Value 是强引用。这意味着当外部没有强引用指向某个 ThreadLocal 实例时该实例可能被 GC 回收此时 Entry.key 会被置为 null。不是 ThreadLocal 本身是弱引用而是 ThreadLocalMap.Entry 的 key 是弱引用。3. ThreadLocalMap 的 Hash 算法索引计算方式index key.threadLocalHashCode (len - 1)与 HashMap 类似。不同点在于ThreadLocal 的 threadLocalHashCode 是全局唯一的由原子递增计数器生成。初始值为 0每次递增 0x61c88647斐波那契数有助于哈希分布更均匀。HashMap 的哈希值依赖于键对象的 hashCode() 方法。4. 数据结构与冲突处理ThreadLocalMap 使用数组结构不使用链表。Hash 冲突解决方式采用线性探测法开放寻址法。如果计算的索引位置被占用则向后查找空槽插入。5. Null Key 的清理机制探测式清理expungeStaleEntry从某个失效 Entry 出发向后清理所有连续的 null Key Entry。同时重新哈希有效的 Entry。启发式清理(cleanSomeSlots)在 set() 操作后触发随机清理 log2(N) 个槽位。防止内存泄漏扩散。Set 操作时也会顺带清理一部分 Entry清理范围有限从当前位置向后清理。类似于“贴羊肉包子的时候顺便清理锅边的渣渣”。Get 操作中如果遇到 Key 为 null 的 Entry也会触发探测式清理。扩容时rehash() / resize()会进行全局清理。(类似于“如果要从一个做羊肉包的小窑的时候换到大窑的时候可以有空一次性清理全部 key 为 null 的 entry”。)6. 扩容机制方法触发条件清理范围行为说明rehash()size 2/3 * len全局清理清理 null Key Entry将无效的清理resize()rehash 后仍 size 0.75 * len全局清理 扩容扩容为 2 倍并将有效 Entry 重新哈希放入新表将有效的拿出来7. set() 和 get() 的原理set()计算索引 → 线性探测 → 插入或覆盖 → 清理 null Entry → 扩容判断get()计算索引 → 若 key 不匹配 → 线性探测查找 → 若发现 null key → 启动探测式清理ThreadLocalMap 的常见问题解析问题1Entry的key-ThreadLocal? k 为什么要设计成弱引用原因: 设计成弱引用的原因内存泄漏的风险当一个 ThreadLocal 实例不再被任何强引用指向时例如用户代码中已经没有对该 ThreadLocal 的引用理论上它应该被垃圾回收。但如果 ThreadLocalMap 的 key 是强引用那么即使外部已经没有对该 ThreadLocal 的引用ThreadLocalMap 仍然持有它的强引用导致它永远无法被回收。这样就会造成 ThreadLocal 实例和对应的 value 都无法被释放从而引发内存泄漏。弱引用避免了这个问题如果 key 是弱引用当外部没有强引用指向某个 ThreadLocal 实例时垃圾回收器会在下一次 GC 时回收该 ThreadLocal 实例。此时ThreadLocalMap 中对应的 key 会变成 null但 value 仍然存在。ThreadLocalMap的清理机制 会在某些时机如插入新条目时清理这些 key 为 null 的条目从而释放 value 的内存。也就是说弱引用可以尽量处理这个内存泄漏的问题但是不能完全解决强引用是直接没办法。完全解决的办法当然是直接remove整个entry弱引用是保底措施。问题2当发生 GC 后ThreadLocalMap 中的 key 是否为 null在使用 ThreadLocal 时一个常见问题是当发生 GC 后ThreadLocalMap 中的 key 是否为 null。以下是所有可能的情况分析1.无外部强引用2.有外部强引用3.线程池复用4.ThreadLocal被重新赋值这个就是改变了引用其实可以当做无外部引用5.线程销毁。✅ 场景 1无外部强引用常见内存泄漏场景描述 ThreadLocal 实例未被任何强引用持有如局部变量使用后未清理。GC 后的状态Key 为 null被回收Value 仍存在内存泄漏代码示例 ThreadLocalString local new ThreadLocal(); local.set(value); local null; System.gc();解决方案调用 remove() 显式清理使用 try-finally 确保清理 ✅ 场景 2有外部强引用描述 ThreadLocal 被静态变量或成员变量引用。GC 后的状态Key 不为 null未被回收Value 正常保留无泄漏代码示例 static ThreadLocalString local new ThreadLocal(); local.set(value); System.gc();解决方案无需处理只要强引用存在GC 不会回收 ✅ 场景 3线程池复用线程描述如果使用 线程池线程会被复用ThreadLocal 的 Value 可能残留。如果 ThreadLocal 被回收但线程未销毁ThreadLocalMap 会积累大量 Entry其中 Key 为 nullValue 无法回收。类似酒店给你的房间房间复用了但是没有打扫卫生。GC 后的状态Key 可能为 nullThreadLocal 被回收Value 仍存在内存泄漏长期运行可能导致 OOM解决方案任务结束时调用 remove()使用 ThreadPoolExecutor.afterExecute() 钩子清理 ✅ 场景 4ThreadLocal 被替换重新赋值描述 ThreadLocal 被重新赋值为新实例旧实例无强引用。GC 后的状态旧 Key 为 null旧 Value 仍存在内存泄漏代码示例 ThreadLocalString local new ThreadLocal(); local.set(old value); local new ThreadLocal(); // 旧对象无强引用 System.gc(); // ThreadLocalMap 中的 Entry // Key: null旧的 ThreadLocal 被回收 // Value: old value内存泄漏解决方案先调用 remove() 再赋值 ✅ 场景 5线程销毁描述当 线程销毁 时ThreadLocalMap 会被回收所有 Entry包括 Key 和 Value都会被 GC 清理。但如果使用 线程池线程不会销毁ThreadLocal 的内存泄漏问题仍然存在。GC 后的状态ThreadLocalMap 被回收所有 Entry 被清理Key 与 Value 都被释放解决方案无需手动清理但线程池场景不适用此机制✅ 最佳实践用完 ThreadLocal 必须调用 remove()避免内存泄漏因为 Entry 的 key 是弱引用value 是强引用GC 后 key 会为 null但 value 仍存在造成内存泄漏推荐使用 try-finally 确保清理避免在线程池中残留 ThreadLocal使用 try-finally 或 afterExecute 清理线程池中线程是复用的不会自动销毁 ThreadLocalMap若不清除Entry 会持续累积可能导致 OOM可使用 ThreadPoolExecutor.afterExecute() 统一清理尽量使用 static final ThreadLocal或至少 final ThreadLocal避免被意外回收或替换。场景1或者场景4final 表示引用不可变防止被置 null 或重新赋值避免因弱引用导致 Key 丢失即使你知道 value 是什么也无法访问static 更适合全局上下文如用户信息、事务 ID 等如果只是对象内部状态非 static 的 final ThreadLocal 也足够问题3ThreadLocalMap的set方法 一、整体流程概览 private void set(ThreadLocal? key, Object value) {Entry[] tab table;int len tab.length;// 1.计算哈希槽int i key.threadLocalHashCode (len - 1); // 2.线性探测查找插入的位置for (Entry e tab[i]; e ! null; e tab[i nextIndex(i, len)]) {ThreadLocal? k e.get();// 3.处理keyif (k key) { // 3.1如果 key 已存在直接覆盖 valuee.value value;return;}if (k null) { // 3.2如果 keynullThreadLocal 被 GC替换旧 EntryreplaceStaleEntry(key, value, i);return;}}// 4.如果没有冲突直接存入新 Entrytab[i] new Entry(key, value);int sz size;// 5.启发式清理 扩容判断if (!cleanSomeSlots(i, sz) sz threshold) {rehash(); // 重新哈希并且扩容} }二、详细流程说明✅ 1. 计算哈希槽 int i key.threadLocalHashCode (len - 1);key.threadLocalHashCode 是一个全局递增的哈希值。初始值为 0每次递增 0x61c88647一个斐波那契数的十六进制值用于均匀分布哈希值。len 是 Entry[] table 的长度2 的幂。使用位运算  (len - 1) 模拟取模提升效率。 ✅ 作用确定插入位置减少哈希冲突。✅ 2. 线性探测开放寻址法 for (Entry e tab[i]; e ! null; e tab[i nextIndex(i, len)]) {// ... }如果当前槽位不为空发生哈希冲突则向后查找空槽nextIndex()。nextIndex(i, len)向后移动一位如果越界则从数组头部开始循环数组。这种方式称为 开放寻址法与 HashMap 的链表法不同。 ✅ 作用解决哈希冲突寻找合适插入位置。✅ 3. 处理 Key 冲突或 Null Key在循环中会遇到以下几种情况 情况 1Key 相同直接覆盖 if (k key) {e.value value;return; }如果当前 Entry 的 key 与插入 key 相同直接更新 value。 情况 2Key 为 nullThreadLocal 被 GC if (k null) {replaceStaleEntry(key, value, i);return; }表示该 Entry 的 key 已被 GC 回收。调用 replaceStaleEntry() 替换并清理该 Entry。该方法内部会调用 expungeStaleEntry()进行 探测式清理清除连续的 null key Entry。 ✅ 作用避免内存泄漏及时清理无效 Entry。✅ 4. 插入新 Entry tab[i] new Entry(key, value); int sz size;如果找到空槽位直接插入新的 Entry。更新 sizeEntry 数量。 ✅ 5. 启发式清理 扩容判断 if (!cleanSomeSlots(i, sz) sz threshold) {rehash(); } private void rehash() {expungeStaleEntries();// Use lower threshold for doubling to avoid hysteresisif (size threshold - threshold / 4)resize();} cleanSomeSlots(i, sz)启发式清理从当前索引开始随机清理 log₂(size) 个槽位。如果清理了至少一个 null key Entry返回 true。 rehash()全局清理 扩容判断调用 expungeStaleEntries() 清理所有 null key Entry。如果清理后仍超过扩容阈值threshold len * 2/3则调用 resize() 扩容。扩容为原来的 2 倍并重新哈希所有的有效 Entry。 ✅ 作用控制内存使用避免 OOM提升性能。 问题4 ThreadLocalMap的清理机制1. .set()方法清理机制的思维导图2. 不同场景下的 set() 行为(1) 最佳情况槽位空闲无冲突无失效Entry操作直接插入新 Entry。附加清理触发 启发式清理cleanSomeSlots以对数复杂度log2(N)的步长扫描部分槽位清理可能的失效 Entry。目的预防性清理减少未来内存泄漏风险。(2) 哈希冲突槽位被有效Entry占用Key不匹配操作线性探测下一个槽位i nextIndex(i, len)。附加清理无立即清理但后续插入可能触发清理。(3) 发现失效EntryKeynull操作触发 替换式清理replaceStaleEntry分为以下步骤向前扫描 从当前槽位向前遍历找到 最早的失效 Entry 位置slotToExpunge。 for (i prevIndex(staleSlot, len); (e tab[i]) ! null; i prevIndex(i, len)) {if (e.get() null) slotToExpunge i; }向后扫描 从当前槽位向后遍历处理两种情况找到相同 Key替换值并调整位置。其他失效 Entry扩展清理范围。探测式清理expungeStaleEntry 从 slotToExpunge 开始向后清理连续失效 Entry并重新哈希有效 Entry。 private int expungeStaleEntry(int staleSlot) {// 清理当前槽位tab[staleSlot].value null;tab[staleSlot] null;size--; ​// 向后遍历清理for (i nextIndex(staleSlot, len); (e tab[i]) ! null; i nextIndex(i, len)) {ThreadLocal? k e.get();if (k null) {// 清理失效 Entry} else {// 重新哈希有效 Entry}}return i; // 返回第一个 null 的位置 } 3. 关键清理方法对比方法触发条件清理范围时间复杂度启发式清理cleanSomeSlots()插入新 Entry 后触发随机扫描 log2(N) 个槽位O(log N)替换式清理replaceStaleEntry()遇到失效 Entry 时触发向前找到链头 向后连续清理O(n)探测式清理expungeStaleEntry()replaceStaleEntry() 内调用清理连续失效 EntryO(n) 4. 设计思想总结乐观插入优先保证插入效率仅在必要时触发清理。惰性清理不完全依赖 set() 清理需手动 remove() 确保安全。局部整理通过重新哈希有效 Entry减少后续操作冲突概率。内存安全弱引用 Key 防止内存泄漏但需配合清理机制。5.清理方式总结清理方式触发条件调用的清理方法清理范围是否完全清理set() 探测式清理遇到 keynull 的 EntryreplaceStaleEntry() 替换式清理 expungeStaleEntry()探测式比下面了多了一段向前扫描局部探测路径遇到一个空槽就停止❌get() 惰性清理遇到 keynull 的 EntryexpungeStaleEntry()局部探测路径❌rehash() 全局清理size thresholdexpungeStaleEntries()清理全部无效的。全局遍历所有位置局部探测⚠️接近完全我觉得是完全✅resize() 完全清理rehash() 后仍需扩容只保留有效到新的容器。全局遍历全部位置重建新表✅
http://www.zqtcl.cn/news/844104/

相关文章:

  • 网站做留言板如何推广小程序商城
  • 金融社区类网站建设鞍山58同城招聘网
  • 网站搭建策划书wordpress 屏蔽插件更新
  • 做网上购物网站杭州房产网官方网站
  • 汕头市网站建设分站公司站长网站大全
  • c2c的网站名称和网址深圳设计公司办公室
  • 建设银行企业版网站做微网站平台
  • 北京企业网站建设电话长沙建设工程信息网
  • 大型综合门户网站开发扁平化个人网站
  • 怎么做代理人金沙网站长沙 网站运营
  • 商城网站开发的目的和意义鲜花类网站建设策划书范文
  • 什么类型的公司需要做建设网站的iis7 网站权限设置
  • 信誉好的商城网站建设火车头 wordpress 发布
  • 龙岩做网站抚顺 网站建设
  • wordpress怎么设置广告位青州网站优化
  • 网站的备案编号高端网站建设谷美
  • 佛山智能网站建设地址设计资溪做面包招聘的网站
  • 荆州网站建设多少钱国外网站设计理念
  • 网站备案成功后wordpress文字加框
  • 中小企业怎么优化网站西安网站建设求职简历
  • 网站开发者模式怎么打开商城网站建设特点有哪些
  • 网站登录按纽是灰色的做网站的前途怎么样
  • 常州城乡建设局网站霸榜seo
  • 网站响应样式如何制作自己的公众号
  • 网站的友情连接怎么做免费收录链接网
  • 太原网站设计排名wordpress 设置语言
  • 南京模板建站定制网站网站单页面怎么做的
  • 宁夏住房建设厅网站石家庄最新今天消息
  • 写网站软件tomcat部署wordpress
  • 怎么做下载网站吗分析一个网站