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

微信小程序安装青岛网站关键词排名优化

微信小程序安装,青岛网站关键词排名优化,金融网站开发,定制网站建设基础步骤本文链接:https://blog.csdn.net/LHQJ1992/article/details/52451136 一、概述 在2017京东校园招聘笔试题中遇到了描述ThreadLocal的实现原理和内存泄漏的问题,之前看过ThreadLocal的实现原理,但是网上有很多文章将的很乱,其中有…

本文链接:https://blog.csdn.net/LHQJ1992/article/details/52451136

一、概述
在2017京东校园招聘笔试题中遇到了描述ThreadLocal的实现原理和内存泄漏的问题,之前看过ThreadLocal的实现原理,但是网上有很多文章将的很乱,其中有很多文章将ThreadLocal与线程同步机制混为一谈,特别注意的是ThreadLocal与线程同步无关,并不是为了解决多线程共享变量问题!
ThreadLocal官网解释:

  This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its {@code get} or {@code set} method) has its own, independently initialized copy of the variable.  {@code ThreadLocal} instances are typically private static fields in classes that wish to associate state with a thread (e.g.,a user ID or Transaction ID)
1
->翻译过来的大概意思就是:ThreadLocal类用来提供线程内部的局部变量。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量,ThreadLocal实例通常来说都是private static类型。
总结:ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。

ThreadLocal的主要应用场景为按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。例如:同一个网站登录用户,每个用户服务器会为其开一个线程,每个线程中创建一个ThreadLocal,里面存用户基本信息等,在很多页面跳转时,会显示用户信息或者得到用户的一些信息等频繁操作,这样多线程之间并没有联系而且当前线程也可以及时获取想要的数据。

二、实现原理
ThreadLocal可以看做是一个容器,容器里面存放着属于当前线程的变量。ThreadLocal类提供了四个对外开放的接口方法,这也是用户操作ThreadLocal类的基本方法:
(1) void set(Object value)设置当前线程的线程局部变量的值。
(2) public Object get()该方法返回当前线程所对应的线程局部变量。
(3) public void remove()将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
(4) protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次,ThreadLocal中的缺省实现直接返回一个null。

可以通过上述的几个方法实现ThreadLocal中变量的访问,数据设置,初始化以及删除局部变量,那ThreadLocal内部是如何为每一个线程维护变量副本的呢?

其实在ThreadLocal类中有一个静态内部类ThreadLocalMap(其类似于Map),用键值对的形式存储每一个线程的变量副本,ThreadLocalMap中元素的key为当前ThreadLocal对象,而value对应线程的变量副本,每个线程可能存在多个ThreadLocal。

源代码:

/**
 Returns the value in the current thread's copy of this
 thread-local variable.  If the variable has no value for thecurrent thread, it is first initialized to the value returned by an invocation of the {@link #initialValue} method.
  @return the current thread's value of this thread-local
 */
public T get() {
    Thread t = Thread.currentThread();//当前线程
    ThreadLocalMap map = getMap(t);//获取当前线程对应的ThreadLocalMap
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);//获取对应ThreadLocal的变量值
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();//若当前线程还未创建ThreadLocalMap,则返回调用此方法并在其中调用createMap方法进行创建并返回初始值。
}
//设置变量的值
public void set(T value) {
   Thread t = Thread.currentThread();
   ThreadLocalMap map = getMap(t);
   if (map != null)
       map.set(this, value);
   else
       createMap(t, value);
}
private T setInitialValue() {
   T value = initialValue();
   Thread t = Thread.currentThread();
   ThreadLocalMap map = getMap(t);
   if (map != null)
       map.set(this, value);
   else
       createMap(t, value);
   return value;
}
/**
为当前线程创建一个ThreadLocalMap的threadlocals,并将第一个值存入到当前map中
@param t the current thread
@param firstValue value for the initial entry of the map
*/
void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//删除当前线程中ThreadLocalMap对应的ThreadLocal
public void remove() {
       ThreadLocalMap m = getMap(Thread.currentThread());
       if (m != null)
           m.remove(this);
}

/**Returns the value in the current thread's copy of thisthread-local variable.  If the variable has no value for thecurrent thread, it is first initialized to the value returned by an invocation of the {@link #initialValue} method.@return the current thread's value of this thread-local*/
public T get() {Thread t = Thread.currentThread();//当前线程ThreadLocalMap map = getMap(t);//获取当前线程对应的ThreadLocalMapif (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);//获取对应ThreadLocal的变量值if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();//若当前线程还未创建ThreadLocalMap,则返回调用此方法并在其中调用createMap方法进行创建并返回初始值。
}
//设置变量的值
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);
}
private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);return value;
}
/**
为当前线程创建一个ThreadLocalMap的threadlocals,并将第一个值存入到当前map中
@param t the current thread
@param firstValue value for the initial entry of the map
*/
void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//删除当前线程中ThreadLocalMap对应的ThreadLocal
public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);
}


上述是在ThreadLocal类中的几个主要的方法,他们的核心都是对其内部类ThreadLocalMap进行操作,下面看一下该类的源代码:

static class ThreadLocalMap {
  //map中的每个节点Entry,其键key是ThreadLocal并且还是弱引用,这也导致了后续会产生内存泄漏问题的原因。
 static class Entry extends WeakReference<ThreadLocal<?>> {
           Object value;
           Entry(ThreadLocal<?> k, Object v) {
               super(k);
               value = v;
   }
    /**
     * 初始化容量为16,以为对其扩充也必须是2的指数 
     */
    private static final int INITIAL_CAPACITY = 16;
    /**
     * 真正用于存储线程的每个ThreadLocal的数组,将ThreadLocal和其对应的值包装为一个Entry。
     */
    private Entry[] table;


    ///....其他的方法和操作都和map的类似
}

static class ThreadLocalMap {//map中的每个节点Entry,其键key是ThreadLocal并且还是弱引用,这也导致了后续会产生内存泄漏问题的原因。static class Entry extends WeakReference<ThreadLocal<?>> {Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}/*** 初始化容量为16,以为对其扩充也必须是2的指数 */private static final int INITIAL_CAPACITY = 16;/*** 真正用于存储线程的每个ThreadLocal的数组,将ThreadLocal和其对应的值包装为一个Entry。*/private Entry[] table;///....其他的方法和操作都和map的类似
}


总之,为不同线程创建不同的ThreadLocalMap,用线程本身为区分点,每个线程之间其实没有任何的联系,说是说存放了变量的副本,其实可以理解为为每个线程单独new了一个对象。

三、内存泄漏问题(参考其他博文)
  内存泄漏在于它的内部有一个map组成,其中map中的key是一个弱引用,弱引用再一次内存回收的时候就会被回收。这个map中存的是单个线程的一些信息,在进行回收之后就会变为null,但是value值还在并且得不到释放就会造成内存泄漏。有些信息用户可能只使用一次,在使用强引用的时候也得不到回收的效果就会造成内存泄漏。

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

相关文章:

  • wordpress ajax很慢seo比较好的优化方法
  • 做网站哪家好 青岛正版seo搜索引擎
  • 做网站备案实名需要钱吗精准营销的成功案例
  • 用织梦做网站能练技术吗如何让百度收录自己的网站信息
  • 怎么编辑网站源代码新媒体营销案例
  • 腾讯云可以做网站吗3seo职业技能培训班
  • 政府网站集约化建设推进会百度帐号注册
  • 丰台路网站建设其他搜索引擎
  • 网站为什么做重定向优秀网站seo报价
  • 关于委托建设网站强化防疫指导
  • 网站建设中布局电商线上推广
  • 宁波网站设计首选荣盛网络宁德市人力资源和社会保障局
  • 科技公司网站建设方案书模板百度灰色词排名代发
  • 淘宝网站c 设计怎么做的品牌营销网站建设
  • 哪家公司做网站开发做得比较好百度指数的数值代表什么
  • 东莞市建设网站培训免费seo软件
  • 做任务有奖励的网站长沙快速排名优化
  • wordpress 头像地址西安seo按天收费
  • 网站制作网站设计营销网站推荐
  • 莆田外贸专业建站关键词排名网站
  • 网站制作的方法网站推广方法有哪些
  • 最大网站建设公司郑州网站建设用户
  • 网站建设和网络搭建是一回事吗系统优化的意义
  • 徐州 网站建设如何做好百度推广
  • 成都锦江建设局网站b2b平台排名
  • 网站开发税点开户推广竞价开户
  • 汽车网站推广策略乐陵seo优化
  • 上海做得好的网站建设公司免费的舆情网站app
  • 兰州展柜公司网站建设线上销售平台有哪些
  • 百货商城网站建设网络营销是什么意思
  • C++20 协程
  • LeetCode 854:相似度为 K 的字符串
  • 小白如何认识并处理Java异常?
  • 构建跨平台远程医疗系统中的视频通路技术方案探究
  • 4麦 360度定位
  • 制造业新突破:AR 培训系统助力复杂操作轻松上手​