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

东莞做网站优化天助网络seo建站收费地震

东莞做网站优化天助网络,seo建站收费地震,flash全屏网站模板,重庆公司社保最低档每月多少钱文章目录1.什么是ThreadLocal?2.ThreadLocal基本用法3.ThreadLocal的应用场景4.ThreadLocal底层原理5.强软弱引用之间的区别5.1强引用5.2软引用5.3弱引用5.4虚引用6.ThreadLocal内存泄漏问题7.如何防止ThreadLocal内存泄漏问题8.ThreadLocal采用的是弱引用9.ThreadL…

文章目录

    • 1.什么是ThreadLocal?
    • 2.ThreadLocal基本用法
    • 3.ThreadLocal的应用场景
    • 4.ThreadLocal底层原理
    • 5.强软弱引用之间的区别
      • 5.1强引用
      • 5.2软引用
      • 5.3弱引用
      • 5.4虚引用
    • 6.ThreadLocal内存泄漏问题
    • 7.如何防止ThreadLocal内存泄漏问题
    • 8.ThreadLocal采用的是弱引用
    • 9.ThreadLocal与Synchronized区别

参考蚂蚁课堂

1.什么是ThreadLocal?

ThreadLocal提供了线程本地变量,它可以保证访问到的变量属于当前线程,每个线程都保存有一个变量副本,每个线程的变量都不同。ThreadLocal相当于提供了一种线程隔离,将变量与线程相绑定。ThreadLocal适用于在多线程情况下,可以实现传递数据,实现线程隔离。

2.ThreadLocal基本用法

可以创建一个TheadLocal的对象然后set是设置内容,get是获取内容。可以做到线程之间变量的隔离。

    public static void main(String[] args) {ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();stringThreadLocal.set("wjz nb");new Thread(() -> {stringThreadLocal.set("wjz mvp");System.out.println("子线程:" + stringThreadLocal.get());}).start();System.out.println("主线程:"+stringThreadLocal.get());}

我们可以开一个主线程在主线程中将ThreadLocal设置为"wjz nb",然后再开一个子线程在子线程中设置stringThreadLocal值为"wjz mvp",然后我们执行这段程序。看看结果如果主线程和子线程的值不同说明ThreadLocal确实隔离了,如果他们两个的值相同说明没隔离。

在这里插入图片描述

结果显示他俩确实是隔离的。

3.ThreadLocal的应用场景

  • 设计模式中的模板方法,他会把一些公有的东西放在模板类类,其他方法交给子类来实现,那么就可以把一些变量缓存在一个模板类当中这样我的子类就可以去获取。

  • SpringMVC获取HttpRequest,首先tomcat接受请求,创建一个线程然后通过Servlet处理请求,SpringMVC对Servlet进行了一层封装,封装了HttpRequest对象放入当前的ThreadLocal然后再通过Aop拦截请求,然后在控制器层的ThreadLocal获取到该HttpRequest。虽然经过了重重处理,但是最终还是在同一个线程里。

    在这里插入图片描述

    比如说下面这段代码我想要获取HttpServletRequest对象,是通过RequestContextHolder获取的我们来看一下这个类里面是啥样的

    在这里插入图片描述

    我们可以看到这里面定义了ThreadLocal专门缓存HttpServletRequest对象,然后我们就可以在控制层通过ThreadLocal获取该线程的HttpServletRequest对象

  • AOP拦截请求,在Aop层缓存一个变量到ThreadLocal中,然后我们可以在控制层拿到这个变量。

4.ThreadLocal底层原理

TheadLocal是通过ThreadLocalMap存放的,ThreadLocalMap中可以存放多个不同的ThreadLocal对象,同一个线程可以通过ThreadLocalMap存放多个ThreadLocal对象。每个ThreadLocal对象只能缓存一个变量值。底层的ThreadLocalMap<ThreadLocal,Object>我们在执行ThreadLocal.get()实际上调用的是threadLocalMap.get(threadLocal),通过这个返回value值。我们看一下源码

    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();}

我们可以看到首先拿到该线程的ThreadLocalMap,然后通过这个map.getEntry里面传入this即当前的ThreadLocal我们能获取到value值。

5.强软弱引用之间的区别

5.1强引用

当内存不足时,JVM开始进行GC,对于强引用对象,就算是出现了OOM也不会对该对象进行回收,死都不会回收。

在这里插入图片描述

如图所示就算堆内存不够了,抛异常也不会回收,这就是强引用。

5.2软引用

当系统内存充足的时候,不会被回收,当系统内存不足时,它会被回收,比如高速缓存就用到过软引用,内存够用时就保留,不够时就回收。下面我们来看一个例子

    public static void main(String[] args) {Object o1 = new Object();SoftReference<Object> softReference = new SoftReference<>(o1);System.out.println("o1:" + o1);System.out.println("软引用对象:" + softReference.get());o1 = null;try {byte[] bits = new byte[30 * 1024 * 1024];} catch (Throwable ex) {} finally {System.out.println("------------------------------------------");System.out.println("o1:" + o1);System.out.println("软引用对象:" + softReference.get());}}

首先我创建一个强引用对象o1,然后再把它设置成软引用,然后将o1置为null,打印o1被置为null前后的对象情况。

在这里插入图片描述

这是在内存充足的情况下,在o1不为null的情况下,o1强引用对象和软引用对象是一样的,o1被置为null之后,程序结束之前执行finally里面的代码,o1已经是null,所以o1为null,但是软引用没有被回收。

当我们设置一下JVM的参数,然后我把当前堆内存最大空间为5M,

在这里插入图片描述

然后突然申请bits一共30M,那肯定不够了,然后再运行看一下结果

在这里插入图片描述

我们可以看到当内存不足时软引用也被回收了。

5.3弱引用

public class WeakReferenceDemo {public static void main(String[] args) {Object o1 = new Object();WeakReference<Object> weakReference = new WeakReference<>(o1);System.out.println(o1);System.out.println(weakReference.get());o1 = null ;System.gc();System.out.println("===============");System.out.println(o1);System.out.println(weakReference.get());}}

在这里插入图片描述

弱引用就是这样,内存空间足够的情况下只要发生GC他也会被回收。

5.4虚引用

虚引用对象,在收集器确定其引用对象可能被回收后排队。虚引用最常用于以比Java终结机制更灵活的方式安排死前清理操作,如果垃圾收集器在某个时间点确定虚引用的对象是可达的,则在该时间或稍后某个时间,它将使引用入队。他的构造器得参数就有这样的一个队列。

    public PhantomReference(T referent, ReferenceQueue<? super T> q) {super(referent, q);}

虚引用的get方法始终返回空。所以一般情况下虚引用没啥大用。为对象生成虚引用关联的唯一目的就是能在这个对象被收集器回收时收到一个系统通知。jdk中的直接内存回收就用到了虚引用,因为直接内存不在jvm管理范围,所以会在堆内存中分配一个对象保存这个堆外内存的引用,这个就是虚引用,一旦这个对象被回收,相应的用户线程就会收到通知并对直接内存进行清理工作。

6.ThreadLocal内存泄漏问题

内存泄漏就是我们申请了内存,但是该内存一直不会被释放。内存溢出就是申请内存,但是实际的内存不足,就是你管你妈要钱,但是你妈没钱。然后我们通过一段小demo描述一下ThreadLocal内存泄漏的问题。

    public static void main(String[] args) {ThreadLocal<String> stringThreadLocal1 = new ThreadLocal<>();stringThreadLocal1.set("wjz");stringThreadLocal1 = null;Thread thread = Thread.currentThread();System.out.println(thread);}

我们先为这个stringThreadLocal设置一个值,然后再把这个置为null,然后打断点看看这个线程里还有没有这个ThreadLocal。

在这里插入图片描述

我们可以来分析一下原因

在这里插入图片描述

如图所示每个线程里面都会有一个ThreadLocalMap,这个里面保存了保存了<ThreadLocal,value>key是ThreadLocal,然后new了一个ThreadLocal,在堆内存中就会出现ThreadLocal对象,并且被栈中的ThreadLocal和ThreadLocalMap的key引用ThreadLocal = null,只会释放堆内存中的空间,而线程中的ThreadLocalMap的key还在引用着new出来的ThreadLocal所以会发生内存泄漏。

7.如何防止ThreadLocal内存泄漏问题

ThreadLocal已经为我们封装好了一个remove方法,这个方法可以不再让ThreadLocalMap中的key继续引用ThreadLocal对象,然后再将ThreadLocal对象置为null,这样的话没人引用ThreadLocal对象,ThreadLocal对象会被回收。

    public static void main(String[] args) {ThreadLocal<String> stringThreadLocal1 = new ThreadLocal<>();stringThreadLocal1.set("wjz");// ThreadLocalMap与堆内存中的ThreadLocal断开引用stringThreadLocal1.remove();//stringThreadLocal1与堆内存中的ThreadLocal断开引用stringThreadLocal1 = null;Thread thread = Thread.currentThread();System.out.println(thread);}

看一下结果

在这里插入图片描述

刚才10号位置存储了我们输入的字符串现在10号位置没了,说明内存泄漏的问题已经解决。然后我们再点进去看一下remove方法。

     public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);}

我们先拿到当前线程对应的ThreadLocalMap如果这个map不为空的话就删除this(ThreadLocal对象),就是切断ThreadLocalMap对堆内存的引用。

在每次set执行的时候会判断一下key是不是为空如果为空他会清除然后重新创建一个key。

        private void set(ThreadLocal<?> key, Object value) {// We don't use a fast path as with get() because it is at// least as common to use set() to create new entries as// it is to replace existing ones, in which case, a fast// path would fail more often than not.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;return;}if (k == null) {replaceStaleEntry(key, value, i);return;}}

如果key为空他会走进这个方法replaceStaleEntry。

            // If key not found, put new entry in stale slottab[staleSlot].value = null;tab[staleSlot] = new Entry(key, value);

如果key不存在,他就会在旧的槽上添加一个新的entry。综上所述ThreadLocal对象在不用的时候一定要调用一下remove()方法。

8.ThreadLocal采用的是弱引用

如果TheadLocalMap中的key对ThreadLocal对象是强引用,那么他必然不会被GC回收,有可能造成内存溢出。当我们将ThreadLocal的引用指向为null,但是每个线程中有自己独立的ThreadLocalMap还一直在继续持有该对象但是由于它是强引用,所以ThreadLocal不会被回收,就会导致内存溢出。我们追踪源码能发现ThreadLocalMap的Entry都是弱引用他继承了WeakReference

        static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}

9.ThreadLocal与Synchronized区别

Synchronized和ThreadLocal都可以实现多线程访问,保证线程安全问题。Synchronized采用当多个线程竞争到同一个资源的时候,最终只能有一个线程访问,采用时间换空间的方式,保证线程安全的问题。而ThreadLocal在每个线程中都有自己独立的局部变量,空间换时间,相互之间都是隔离,相比来说ThreadLocal效率比Synchronized效率更高。

http://www.lbrq.cn/news/2494927.html

相关文章:

  • 拍卖 网站 建设外贸网络推广服务
  • 哪里可以上传自己的php网站南宁网站seo大概多少钱
  • 乌克兰设计网站建设公司专业网站建设
  • 广州做公司网站推广计划怎么做
  • 哪些网站可以做招商广告语衡阳seo外包
  • 成都工程建设信息网站个人怎么做推广
  • 做3d ppt模板下载网站有哪些蜂蜜网络营销推广方案
  • 服务哪家好网站制作下载百度搜索
  • 湖北智能网站建设找哪家可以搜任何网站的浏览器
  • 珠海中企网站建设seo全站优化全案例
  • seo网站推广简历网络广告营销典型案例
  • 呼市网站设计关键词排名查询网站
  • 网站设计宽屏成年培训班有哪些
  • 校园网站建设情况说明书成品网站货源1
  • 企业网站源码 html今日新闻最新头条10条内容
  • 新浪sae可以做网站么网络优化大师app
  • 宁波网站建设公司推荐易企网seo测试
  • 云南公司建网站多少钱郑州seo建站
  • 微网站特点中国十大热门网站排名
  • 建网站开源代码百度关键词竞价排名
  • 北京网站建设软件鞍山seo公司
  • 万柳网站建设百度服务中心
  • seo教程大秦英扬优化网站的意思
  • 专业做网站建设药品销售推广方案
  • 淘宝不能开网站建设店铺吗百度官方推广平台
  • 长沙网络公司网站百度品牌专区怎么收费
  • 沈阳市和平区网站建设网站优化要做哪些
  • wordpress隐藏菜单石家庄seo排名外包
  • 网站建设合同附加协议百度搜首页
  • 网站建设合作注册一个网站
  • maven 打包报错 process terminated
  • MQTT之“SUBSCRIBE报文和SUBACK报文”
  • Keil MDK 嵌入式开发问题:warning: #223-D: function “sprintf“ declared implicitly
  • 尝试几道算法题,提升python编程思维
  • C++连接MySQL完整教程
  • STM32与ADS1220实现多通道数据采集的完整分析和源程序