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

朔州做网站建立多多少钱

朔州做网站,建立多多少钱,WordPress实验室,微信小程序开发工具官网入口1. ThreadLocal 的概念 ThreadLocal 是 Java 中的一个类,用于实现线程本地存储。它允许你创建一个变量,这个变量在每个线程中都有自己独立的副本,不同线程之间的副本互不干扰。换句话说,ThreadLocal 提供了一种线程隔离的机制&am…

1. ThreadLocal 的概念

ThreadLocal 是 Java 中的一个类,用于实现线程本地存储。它允许你创建一个变量,这个变量在每个线程中都有自己独立的副本,不同线程之间的副本互不干扰。换句话说,ThreadLocal 提供了一种线程隔离的机制,使得每个线程都可以拥有自己的变量实例。

1.1 ThreadLocal 的基本用法
ThreadLocal<String> threadLocal = new ThreadLocal<>();// 在主线程中设置值
threadLocal.set("Main Thread Value");// 在子线程中设置值
new Thread(() -> {threadLocal.set("Child Thread Value");Log.d("ThreadLocal", "Child Thread: " + threadLocal.get()); // 输出: Child Thread Value
}).start();// 在主线程中获取值
Log.d("ThreadLocal", "Main Thread: " + threadLocal.get()); // 输出: Main Thread Value
1.2 ThreadLocal 的工作原理

ThreadLocal 内部维护了一个 ThreadLocalMap,这个 ThreadLocalMap 是每个线程私有的。当你调用 ThreadLocal.set(value) 时,实际上是将 value 存储在当前线程的 ThreadLocalMap 中,键是 ThreadLocal 实例本身。当你调用 ThreadLocal.get() 时,会从当前线程的 ThreadLocalMap 中获取与 ThreadLocal 实例关联的值。


2. ThreadLocal 剖析

概念很简单,一看就会,但让你详细介绍下其原理,那可能就懵比了,问原理,我会概念:)

既然,ThreadLocal 是用于实现线程本地存储,那么它和 Thread 的关系是怎样的呢?

ThreadLocal 的数据之所以与线程绑定,是因为其内部实现依赖于每个线程私有的存储空间。具体来说,ThreadLocal 利用了线程内部的 ThreadLocalMap 来存储和管理每个线程独立的数据副本。

public class Thread implements Runnable {// 每个线程私有的 ThreadLocalMapThreadLocal.ThreadLocalMap threadLocals;// 其他成员和方法...
}
2.1 每个线程都有自己的 ThreadLocalMap

在Java中,每个 Thread 都有一个名为 threadLocals 的成员变量,类型为 ThreadLocal.ThreadLocalMap,它是线程私有的,其他线程无法访问。ThreadLocalMap 是一个自定义的哈希表,其Entry结构如下:

static class Entry extends WeakReference<ThreadLocal<?>> {Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
}

可以看出,Entry 继承自 WeakReference<ThreadLocal<?>>,这意味着对 ThreadLocal 实例的引用是弱引用,而 value 则是强引用,这个就是 ThreadLocal 会造成内存泄漏的关键点,后面详细分析。

弱引用WeakReference)在垃圾回收(GC)中的行为如下:

弱引用对象:如果一个对象只被弱引用所引用,而没有强引用(Strong Reference)指向它,那么在下一次垃圾回收时,这个对象就会被回收掉。
应用场景:弱引用常用于实现缓存等需要在不阻止对象被回收的情况下引用对象的情况。

ThreadLocalMap 中,使用弱引用可以确保当没有其他强引用指向某个 ThreadLocal 实例时,该实例可以被垃圾回收,从而避免因为 ThreadLocal 实例本身无法被回收而导致整个 Entry 一直存在。

2.2 ThreadLocal 存储数据

通过ThreadLocalset方法可以看到 set 值的时候,通过获取当前线程 获取 ThreadLocalMap ,threadLocals,如果获取到了 就拿当前的 ThreadLocal 为键,存储当前值,如果为null,就代表还为初始化,就初始化赋值,然后将 ThreadLocal 实例作为键,将 value 作为值,存储到 threadLocals 中。

public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);
}ThreadLocalMap getMap(Thread t) {return t.threadLocals;
}void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}
2.3 ThreadLocal 存储数据

get值的时候,同样是获取当前线程 获取 ThreadLocalMapthreadLocals,如果获取到了,就用当前的 ThreadLocal去拿对应的值,为null 不存在,则返回初始值,内部就是 初始化 threadLocals 和存入并返回null值。

public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();
}

可以看出,之所以与线程这么强相关,就是每次读取都要通过Thread.currentThread()获取当前线程,然后再去操作数据,而所有的数据都在 Thread 中的 threadLocals进行存储,这下是不是瞬间清楚它们的关系了。

2.4 线程隔离的机制

因为每个线程都有自己的 threadLocals ,并且 ThreadLocal以自身为键,存储数据,每个线程都可以独立获取自己的ThreadLocal` 值,线程之间互不影响,对其他线程数据不可见,确保线程存储私有性。


3. 关于 ThreadLocal 会导致内存泄漏问题

先来看下ThreadLocalMap 的结构

键(Key)ThreadLocal 实例,通过 WeakReference 引用。
值(Value):存储的对应值,强引用。

弱引用的特性​​:如果一个对象只被弱引用指向,而没有强引用指向它,那么在下一次垃圾回收时,这个对象会被回收。

注意是只被!代表其他地方已经不再使用了,已经是垃圾了,才会被回收,而不当GC到来时,弱引用对象就没了,我之前对此有过疑惑,再这里再强调下。

根据内存泄漏定义:长生命周期对象引用了短生命周期对象可知ThreadLocalMapkeyThreadLocal 的弱引用(WeakReference),但 value是强引用,如果 ThreadLocal 本身被 GC 回收了,但 Thread 一直存活(如线程池中的线程),那么 value 就不会被清除,从而造成内存泄漏。

引用链示意图

Thread (线程池中的线程)
└── threadLocals : ThreadLocalMap└── Entry[] table└── Entry : WeakReference<ThreadLocal> → null (ThreadLocal 已被回收)└── value → [object]  (value 强引用未被清理)

这个 value 虽然没有人用了,但由于它还在 ThreadLocalMap 中,所以不会被 GC,造成内存泄漏。
解决的办法也很简单,手动调用下 ThreadLocal.remove()

最后再明确一下概念,每个ThreadLocal 只保存一个值,多次 set 不会叠加数据,而是会替换原有值,真正的内存泄漏风险来自未清理的 value 而非 set 操作本身,由于ThreadLocal 是直接操作当前线程,数据的存储最终是保存在 ThreadThreadLocalMap 中,由 threadLocals 统一管理。

结束了么?并没有,既然要剖析,那就再多了解一点吧;

4. ThreadLocal 中 set 方法源码分析

private void set(ThreadLocal<?> key, Object value) {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;  // 情况1:键已存在,直接更新值return;}if (k == null) {      // 情况2:发现过期EntryreplaceStaleEntry(key, value, i);return;}}tab[i] = new Entry(key, value); // 情况3:新增Entryint sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();
}

ThreadLocalMap 使用开放地址法解决哈希冲突。

从初始索引开始,遍历 ThreadLocalMap 中的槽位,查找是否已经存在相同的 ThreadLocal 键。

主要包括三种处理情况:键存在、键过期、键不存在。
注意ThreadLocal<?> k = e.get();其中 e.get()是获取 ThreadLocal的引用,如果已经被GC回收了,则返回null,如果遇到 keynullEntry,表示这是一个过期的条目(由于弱引用被回收),调用 replaceStaleEntry 方法来替换这个过期条目,注意,replaceStaleEntry 内部仍会调用 cleanSomeSlots 进行尝试清理链表,维持哈希表结构。

最后是尝试清理一些过期的条目,如果清理后仍然达到阈值,则进行扩容操作。

所以可知,即使不显式调用 remove 方法的情况下,ThreadLocalMap 内部的 cleanSomeSlots 方法仍然有可能帮助清理过期的数据,只是有概率会,但这并不保险,最好还是手动调用 remove 方法。


再补充个知识点,ThreadLocalMap 在插入数据时 也会产生哈希冲突, 但于 HashMap 的方式有相似之处,但又有明显不同

ThreadLocalMap 使用开放地址法(线性探测 + 扫描回环)处理哈希冲突,而不是像 HashMap 那样用链表或红黑树。它是一个固定长度的数组,冲突时会向后一个个找空位(或可复用的 stale 位置),必要时回环头部,并会定期清理 stale(已过期)项。

想要详细了解可以慢慢分析 replaceStaleEntry方法。

相同的,就算产生了hash冲突,在 get 时,它从 hash 计算出的索引开始,向后线性探测,逐个比较 entry.get() == 当前ThreadLocal对象,一旦找到匹配,就返回 value。由于插入时也是按此顺序探测,因此一定能找回来。


5. 最后

看完你应该对ThreadLocal有个全新的认识了,虽然概念很容易理解,但我们知其然更要知其所以然。通过现象看本质。


文章转载自:

http://FrVLKl14.qhjkz.cn
http://TyYtTbrM.qhjkz.cn
http://CBwAzChb.qhjkz.cn
http://Bf8vfWcn.qhjkz.cn
http://c8L6I4VR.qhjkz.cn
http://A5zWgzyp.qhjkz.cn
http://GtuCffgH.qhjkz.cn
http://8IrEMqxn.qhjkz.cn
http://gRCptIJe.qhjkz.cn
http://4frGIWga.qhjkz.cn
http://oDCEQjwz.qhjkz.cn
http://MFFX75SJ.qhjkz.cn
http://eqKQNOAV.qhjkz.cn
http://z7xEc0ht.qhjkz.cn
http://1x9yxBq7.qhjkz.cn
http://quwSWQZn.qhjkz.cn
http://TTE3CGLx.qhjkz.cn
http://bk7GYQck.qhjkz.cn
http://PEwdRhqk.qhjkz.cn
http://eG3VZYKC.qhjkz.cn
http://xTcIpdH3.qhjkz.cn
http://581acrR0.qhjkz.cn
http://sFt7NSBA.qhjkz.cn
http://Jxub60cG.qhjkz.cn
http://NvqJLWdn.qhjkz.cn
http://7poOOrx2.qhjkz.cn
http://IgyFEmuw.qhjkz.cn
http://mF7Mompg.qhjkz.cn
http://svVta3EU.qhjkz.cn
http://xJ97I5Bf.qhjkz.cn
http://www.dtcms.com/wzjs/675845.html

相关文章:

  • 网站开发的项目流程图ui设计线上培训
  • 深圳专业网站建设制作价格做淘宝那样的网站
  • 电子商务网站建设答辩记录天津响应式网页建设公司
  • 网站建设服务亮点如何推广自己的微信
  • 廊坊建站软件为什么做网站备案的人态度差
  • 免费建网站平台哪个好ftp做网站
  • 湖北可以做网站的公司兰州网络推广优化网
  • 网站注册转化率电商之家官网
  • 苏州网站设计公司哪家便宜制作网站首先要知道什么
  • 创意礼物网站建设与管理设计效果图怎么收费
  • 南宁网页制作招聘网厦门seo关键词优化代运营
  • 一个人做网站要多久h5页面的制作工具有哪些
  • 扫描到网站目录然后怎么做个人备案 做网站
  • 安康网站建设公司django做的购物网站
  • 企业网站的域名是该企业的什么佛山做网站那家好
  • 网站建设一条龙全包网站界面要素
  • 电子政务网站建设出版社wordpress怎么破解付费插件
  • wordpress企业站源码广元市建设局网站
  • 网站建设优秀网站建兰州网站优化软件
  • ps做网站效果图尺寸如何最重要的网站
  • 冷库建设网站静态网站登陆怎么做
  • 最牛html5网站建设wordpress怎么私人媒体库
  • 哪个网站做简历免费开发网站需求设计
  • dw建网站具体步骤360免费wifi可以破解wifi密码吗
  • 现在个人网站怎么备案南京网站建设咨询
  • 淘宝网站icp备案网站备案最多需要多久
  • 做网站系统的答辩ppt范文福州房产网站建设
  • 西安北郊网站维护运营云南网站制作公司
  • wordpress安装无法登录长沙网站优化体验
  • 站外推广策划书徐州seo关键词