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

深圳手机端网站建设专业公司网站服务器

深圳手机端网站建设专业公司,网站服务器,晋城市住房和城乡建设局官方网站,网站打开速度慢跟什么有关系优质博文:IT-BLOG-CN 从 ThreadLocalMap看 ThreadLocal使用不当的内存泄漏问题 【1】基础概念 : 首先我们先看看ThreadLocalMap的类图,我们知道 ThreadLocal只是一个工具类,他为用户提供get、set、remove接口操作实际存放本地变…

优质博文:IT-BLOG-CN

从 ThreadLocalMap看 ThreadLocal使用不当的内存泄漏问题

【1】基础概念 : 首先我们先看看ThreadLocalMap的类图,我们知道 ThreadLocal只是一个工具类,他为用户提供getsetremove接口操作实际存放本地变量的threadLocals(调用线程的成员变量),也知道 threadLocals是一个ThreadLocalMap类型的变量,下面我们来看看ThreadLocalMap这个类。在此之前,我们回忆一下Java中的四种引用类型链接

【2】分析ThreadLocalMap内部实现: 我们知道ThreadLocalMap内部实际上是一个Entry数组private Entry[] table,我们先看看Entry的这个内部类

/*** 是继承自WeakReference的一个类,该类中实际存放的key是指向ThreadLocal的弱引用和与之对应的value值(该value值* 就是通过ThreadLocal的set方法传递过来的值)由于是弱引用,当get方法返回null的时候意味着回收引用*/
static class Entry extends WeakReference<ThreadLocal<?>> {/** value就是和ThreadLocal绑定的 */Object value;//k:ThreadLocal的引用,被传递给WeakReference的构造方法Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
}
//WeakReference构造方法(public class WeakReference<T> extends Reference<T> )
public WeakReference(T referent) {super(referent); //referent:ThreadLocal的引用
}//Reference构造方法
Reference(T referent) {this(referent, null);//referent:ThreadLocal的引用
}Reference(T referent, ReferenceQueue<? super T> queue) {this.referent = referent;this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}

在这里插入图片描述

在上面的代码中,我们可以看出,当前ThreadLocal的引用k被传递给WeakReference的构造函数,所以ThreadLocalMap中的keyThreadLocal的弱引用。当一个线程调用ThreadLocalset方法设置变量的时候,当前线程的 ThreadLocalMap就会存放一个记录,这个记录的key值为ThreadLocal的弱引用,value就是通过set设置的值。如果当前线程一直存在且没有调用该ThreadLocalremove方法,如果这个时候别的地方还有对ThreadLocal的引用,那么当前线程中的ThreadLocalMap中会存在对ThreadLocal变量的引用和 value对象的引用,是不会释放的,就会造成内存泄漏。

考虑这个ThreadLocal变量没有其他强依赖,如果当前线程还存在,由于线程的ThreadLocalMap里面的key是弱引用,所以当前线程的ThreadLocalMap里面的ThreadLocal变量的弱引用在gc的时候就被回收,但是对应的value还是存在的这就可能造成内存泄漏(因为这个时候 ThreadLocalMap会存在keynull但是value不为nullentry )。

ThreadLocalMap中的Entrykey使用的是ThreadLocal对象的弱引用,在没有其他地方对ThreadLocal依赖,ThreadLocalMap中的ThreadLocal对象就会被回收掉,但是对应的value不会被回收,这个时候Map中就可能存在keynull但是value不为null的项,这需要实际使用的时候使用完毕及时调用 remove方法避免内存泄漏。

如果使用线程池,由于线程可能并不是真正的关闭(比如newFixedThreadPool会保持线程一只存活)。因此,如果将一些大对象存放到ThreadLocalMap中,可能会造成内存泄漏。因为线程没有关闭,无法回收,但是这些对象不会再被使用了。如果希望及时回收对象,则可以使用Thread.remove()方法将变量移除。

ThreadLocal<Object> threadLocal = new ThreadLocal<>();
// 存储数据
threadLocal.set(someData);
// 使用完毕后清除
threadLocal.remove();

我们再看下ThreadLocal底层的源码:

public T get() { //获取当前线程Thread t = Thread.currentThread();  //获取当前线程的ThreadLocalMap变量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();  
}public void set(T value) {  Thread t = Thread.currentThread();  ThreadLocalMap map = getMap(t);  if (map != null)  map.set(this, value);  else  createMap(t, value);  
}public void remove() {  ThreadLocalMap m = getMap(Thread.currentThread());  if (m != null)  m.remove(this);  
}

remove()方法逻辑比较简单,首先获取当前线程的ThreadLocalMap对象,然后循环遍历key,将目标key以及对应的value都设置为null

private void remove(ThreadLocal<?> key) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCode & (len-1);// 循环遍历目标key,然后将key和value都设置为nullfor (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {if (e.get() == key) {e.clear();// 清理value值expungeStaleEntry(i);return;}}
}

使用try-with-resourcestry-finally块:如果你的ThreadLocal变量在需要清理的资源管理上下文中使用,可以使用try-with-resources(自动清理)或try-finally(手动清理)块来确保及时清理。

try (ThreadLocalResource resource = new ThreadLocalResource()) {// 使用 ThreadLocalResource
}
// 或者使用 try-finally
ThreadLocalResource resource = new ThreadLocalResource();
try {// 使用 ThreadLocalResource
} finally {resource.close(); // 在 close 方法中清理 ThreadLocal 变量
}

使用InheritableThreadLocal:如果需要在子线程中访问父线程的ThreadLocal变量,并且确保在子线程中正确清理,可以考虑使用InheritableThreadLocal。这个类允许子线程继承父线程的ThreadLocal变量,并在子线程完成后自动清理。

ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
threadLocal.set("Hello, Parent Thread");
Runnable childTask = () -> {String value = threadLocal.get(); // 子线程可以访问父线程的 ThreadLocal 变量// ...
};
Thread childThread = new Thread(childTask);
childThread.start();
http://www.tj-hxxt.cn/news/2936.html

相关文章:

  • 怎么做网站不会被屏蔽免费建站网站
  • .top和网站宝鸡网站seo
  • 上海杨浦网站建设免费网站流量统计
  • 做彩页素材的网站今日国内最新新闻
  • 怎么做班级网站百度官网网站首页
  • 太古楼角原网站建设如何建立网站服务器
  • 政府工程招标网站杭州seo代理公司
  • 路北网站制作一键关键词优化
  • 淘宝客网站建设任务成人培训机构
  • 用时时彩做网赚的网站是真的吗单页网站怎么优化
  • 建设网站时候应该注意哪些商丘网站seo
  • 网站做跳转谷歌seo运营
  • 日本插画网站有哪些扫描图片找原图
  • 网站里面发消息怎么做超链接网站查询器
  • vs 网站项目网络营销专业是干嘛的
  • 一个企业为什么要建设网站app推广代理
  • 万州哪里有做网站的最新军事新闻今日最新消息
  • 做泥水上哪个网站找事做免费大数据平台
  • 好用的在线设计网站百度关键词优化曝光行者seo
  • 浙江做网站公司排名国外搜索引擎优化
  • 企业网站建设预算表站外推广
  • 浏览器网站免费进入北京网站营销与推广
  • wordpress默认后台登陆地址重庆网站快速排名优化
  • 北京城乡建设厅网站互联网推广销售是做什么的
  • phpcms适合做什么网站网站建设优化的技巧
  • 免费建站个人网站流量宝官网
  • 微博网站开发与设计开题报告长沙靠谱关键词优化服务
  • wordpress模板怎么修改字体淄博seo
  • 做速卖通代码的网站附近的成人电脑培训班
  • 做现货黄金的金融网站网站的营销推广