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

深圳html5网站建设百度广告运营

深圳html5网站建设,百度广告运营,做餐厅网站的需求分析报告,亦庄做网站ThreadLocal也是面试题中十分常见的问题,我是在大部分人的启蒙项目苍穹外卖接触到ThreadLocal这个概念的,苍穹外卖把用户id存在ThreadLocal中来进行权限检验,这是我所了解到的ThreadLocal的第一个用处。 在上次字节面试时被面试官狠狠拷打了…

ThreadLocal也是面试题中十分常见的问题,我是在大部分人的启蒙项目苍穹外卖接触到ThreadLocal这个概念的,苍穹外卖把用户id存在ThreadLocal中来进行权限检验,这是我所了解到的ThreadLocal的第一个用处。

在上次字节面试时被面试官狠狠拷打了ThreadLocal,从概念问到了底层,而我只背了八股,了解到ThreadLocal底层是个map,有弱引用,在面试官反复的反问上败下阵来,今天又是我一个小实习生摸鱼的一天,决定看一看ThreadLocal源码,看一看他到底是何方神圣。

ThreadLocal简介

ThreadLocal 是 Java 中用于实现线程局部变量的类,它能够在多线程环境下,为每个线程提供独立的变量副本,从而避免线程间的数据竞争。

核心作用

  • 线程隔离:每个线程操作自己的变量副本,互不干扰。

  • 避免同步:不需要加锁(如 synchronizedsynchronized),提高并发性能。

  • 典型应用

    • Spring 的事务管理(TransactionSynchronizationManager)

    • 用户会话信息存储(如 Session)

    • JDBC 连接管理(避免线程间共享Connection)

ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。ThreadLocal 变量通常被private static修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。

总的来说,ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景。

 ThreadLocal原理

 ThreadLocal的set()方法

public void set(T value) {Thread t = Thread.currentThread();  // 获取当前线程ThreadLocalMap map = getMap(t);     // 获取线程的 ThreadLocalMapif (map != null) {map.set(this, value);  // 如果 map 已存在,直接设置值} else {createMap(t, value);   // 否则初始化 ThreadLocalMap}
}

 从上面的代码可以看出,ThreadLocal  set赋值的时候首先会获取当前线程thread,并获取thread线程中的ThreadLocalMap属性。如果map属性不为空,则直接更新value值,如果map为空,则实例化threadLocalMap,并将value值初始化。

那么第二个问题来了,ThreadLocalMap是什么?

ThreadLocalMap实现

static class ThreadLocalMap {/*** The entries in this hash map extend WeakReference, using* its main ref field as the key (which is always a* ThreadLocal object).  Note that null keys (i.e. entry.get()* == null) mean that the key is no longer referenced, so the* entry can be expunged from table.  Such entries are referred to* as "stale entries" in the code that follows.*/static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}}

可看出ThreadLocalMap是ThreadLocal的内部静态类,用于存储线程的局部变量,而它的构成主要是用Entry来保存数据 ,而且还是继承的弱引用(常用考点)。在Entry内部使用ThreadLocal作为key,使用我们设置的value作为value。每个线程都有一个独立的 ThreadLocalMap,存储该线程的所有 ThreadLocal 变量。

ThreadLocalMap的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)]) {if (e.refersTo(key)) {  // 如果 key 已存在,更新 valuee.value = value;return;}if (e.refersTo(null)) {  // 如果 key 已被回收(弱引用),替换过期 EntryreplaceStaleEntry(key, value, i);return;}}tab[i] = new Entry(key, value);  // 插入新 Entryint sz = ++size;if (!cleanSomeSlots(i, sz) && sz >= threshold) {rehash();  // 扩容}
}

ThreadLocalMap的getEntry()方法

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 {return getEntryAfterMiss(key, i, e);  // 线性探测查找}
}

ThreadLocal的get()方法

public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);  // 获取当前 ThreadLocal 对应的 Entryif (e != null) {@SuppressWarnings("unchecked")T result = (T) e.value;return result;}}return setInitialValue();  // 如果不存在,初始化并返回默认值
}private T setInitialValue() {T value = initialValue();  // 默认返回 null,可重写Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {map.set(this, value);} else {createMap(t, value);}return value;
}

ThreadLocal的remove()方法

public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null) {m.remove(this);  // 从 ThreadLocalMap 中移除当前 ThreadLocal}
}

调用 remove() 方法会直接从当前线程的 ThreadLocalMap 中删除对应的 ThreadLocal 键值对。这一操作的核心目的是防止内存泄漏。

ThreadLocal 的内存泄漏问题

ThreadLocalMap使用 ThreadLocal的弱引用作为 key,弱引用的特性是:如果某个对象仅被弱引用关联,垃圾回收(GC)时会自动清理该对象。因此,如果 ThreadLocal未被外部强引用持有,GC 时会回收 ThreadLocal实例,导致 ThreadLocalMap中的 key 变为 null。

然而,ThreadLocalMap中的 value 仍然是强引用,即使 key 被回收,value 也不会被自动清理。这会导致 ThreadLocalMap中存在大量 key 为 null但 value 仍占用内存的条目,从而引发内存泄漏。

线程复用与内存泄漏的关联

ThreadLocal的变量生命周期与线程绑定。在线程池场景下,线程通常会被复用,导致线程的生命周期可能极长(甚至与 JVM 生命周期一致)。如果未及时清理 ThreadLocal变量(如未调用 remove() 或替换值),其存储的数据会一直堆积。

ThreadLocal与Thread,ThreadLocalMap的关系

图片来自于史上最全ThreadLocal 详解(一)-CSDN博客。从图中可以看出三者之间的关系。

关于ThreadLocal的常见面试题

4.1 ThreadLocal 和 synchronized 的区别?

对比项ThreadLocalsynchronized
数据隔离方式每个线程独立副本共享数据 + 锁
性能无锁,更高性能有锁,可能阻塞
适用场景线程隔离数据(如 Session)线程共享数据(如计数器)

4.2 ThreadLocal 的 key 为什么是弱引用?

  • 防止内存泄漏

    • 如果 ThreadLocal被回收,Entry 的 key 会自动被 GC 清理,避免 ThreadLocal无法回收。

  • 但 value 仍需手动清理

    • 因为 value 是强引用,需要 remove() 或 set(null)。

4.3 ThreadLocal 的 key 为什么不设为强引用?

在业务代码中使用完ThreadLocal后,即使ThreadLocal引用被回收,由于ThreadLocalMap的Entry强引用了ThreadLocal(ThreadLocal作为key),导致ThreadLocal对象无法被回收。当没有手动删除Entry且当前线程仍在运行时,会形成一条强引用链:当前线程引用→当前线程→ThreadLocalMap→Entry。这个Entry包含了ThreadLocal实例和value,因此不会被回收,从而造成内存泄漏。换言之,由于ThreadLocalMap的key采用强引用机制,内存泄漏问题无法完全避免。

以上就是关于ThreadLocal的一些解析与想法。

http://www.dtcms.com/wzjs/402343.html

相关文章:

  • 淮安网站建设费用推广优化工具
  • html网站后台管理系统网址链接查询
  • 制作网站服务器营销推广方案怎么写
  • 运城环保局网站王建设站内优化seo
  • 网站宣传与推广的指导思想个人网站制作软件
  • 游戏网站做代理seo搜索引擎优化工作内容
  • 做购物网站多少钱百度app打开
  • 炫酷的网站设计搜索引擎调价平台哪个好
  • 温州公司网站建设2022最近热点事件及评述
  • 如何自己做解析网站百度定位店铺位置怎么设置
  • 网站建设专业的公司排名2023年10月疫情恢复
  • 湛江高端网站建设百度广告投放公司
  • 重庆网站建设选卓光网络营销热点事件案例分析
  • 湖州网站设计建设网站开发需要哪些技术
  • 司机找事做那个网站靠谱徐州seo排名收费
  • 百度上传网站服务器怎么做游戏推广员
  • 高安网站找工作做面点事怎么在百度上做推广上首页
  • 中文网址和中文域名巩义网站优化公司
  • 商标设计软件免费版厦门seo关键词排名
  • 建设部网站示范文本网站百度
  • 网站建设方案大全网站推广的软件
  • 电子商务网站数据库怎么做学生个人网页制作
  • 三网合一网站建设程序制作网页的基本步骤
  • 成功卡耐基网站建设今天的国际新闻
  • 许昌做网站公司汉狮价格百度竞价
  • 做五金出口在哪个网站好点市场宣传推广方案
  • html炫酷特效代码关键词优化如何做
  • 个人响应式网站外链代发平台
  • 可以做进销存的网站系统my63777免费域名查询
  • 美国一个分享怎么做的网站叫什么网站推广怎么优化