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

宝安住房和建设局网站电话百度竞价网站

宝安住房和建设局网站电话,百度竞价网站,虚拟主机与网站建设,网站打开乱码使用ThreadLocal可以为每个线程维护一个线程变量,使用场景为线程间隔离,线程内方法共享; 原理: Thread类中有一个实例属性ThreadLocalMap,ThreadLocalMap中存放的是Entry数组,Entry数组是ThreadLocal和Ob…

使用ThreadLocal可以为每个线程维护一个线程变量,使用场景为线程间隔离,线程内方法共享;

原理:

Thread类中有一个实例属性ThreadLocalMap,ThreadLocalMap中存放的是Entry数组,Entry数组是ThreadLocal和Object的键值对;源码如下--

Thread类:

/** ThreadLocal values pertaining to this thread. This map is maintained* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals;

ThreadLocal->ThreadLocalMap->Entry类:

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

ThreadLocal有一个内部静态类ThreadLocalMap, ThreadLocalMap是一个Entry数组,通过map方法来访问数据,而Entry对key(ThreadLocal实例对象)的引用使用了虚引用;这里导致key可能会在JVM判断oom之前将key回收掉,导致内存泄漏-此时key对应的ThreadLocal对象被回收变成null,而value存在Thread reference->thread->threadlocalMap->entry-value的强引用链,导致无法回收;虽然在ThreadLocal的get和set以及remove方法中实现了检查是否存在key为null并清理value的机制,但是无法避免内存短时间内泄露的问题;

看一下ThreadLocal的set()和get()方法--

public void set(T value) {set(Thread.currentThread(), value);}private void set(Thread t, T value) {ThreadLocalMap map = getMap(t);if (map != null) {map.set(this, value);} else {createMap(t, value);}}ThreadLocalMap getMap(Thread t) {return t.threadLocals;}
public T get() {return get(Thread.currentThread());}private T get(Thread t) {//获取当前线程的ThreadLocalMapThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {T result = (T) e.value;return result;}}return setInitialValue(t);}private Entry getEntry(ThreadLocal<?> key) {//这里进行map操作和hashmap的原理基本是一样的,hashcode按位与数组长度减一,数组长度默认为16,(2的n次方减一值做按位与相当于取模,保证了散列均衡)int i = key.threadLocalHashCode & (table.length - 1);Entry e = table[i];if (e != null && e.refersTo(key))return e;elsereturn getEntryAfterMiss(key, i, e);}

所以,ThreadLocal维护为每一个线程维护线程变量副本的原理在于,每个线程对象会创建自己的THreadLocalMap--这里并非主动创建,而是调用THreadLocal的set或者get方法的时候才创建;而ThreadLocalMap则是一个以ThreadLocal实例对象的弱应用为key,Object对象为value的键值对数组,以便每个线程对象存放多个线程变量,而对这个线程变量的访问是通过ThreadLocal对象来操作的,所以说实现线程变量的根本不在于ThreadLocal,而是ThreadLocalMap,而ThreadLocal对象只是访问该线程的ThreadLocalMap的一个入口,由于get(Thread t)和set(Thread t,T value)都是私有方法,通过其他对象无法访问,所以只能通过ThreadLocal对象提供的重载方法get()和set(Object value)来访问,保证了线程变量的安全性---其他线程无法修改另外一个线程的ThreadLocalMap;所以核心是getMap(Thread t),而这里的线程对象t只能是Thread.currentThread;

另外需要注意的是,对ThreadLocal 保存的线程变量一定要在使用完之后及时remove掉,一个原因是防止内存泄漏,更重要的原因是在线程池场景下,一个请求可能会读取到上一个请求保存的变量内容,从而造成业务逻辑上的BUG,而且这种BUG还是不易排查的;

另外关于内存泄露的问题JDK提供了一些保障,分为启发式清理和探测式清理--

探测式清理--

原理:

  1. 删除当前元素;
  2. 继续往后遍历,
    1. 当key=null的时候,删除value
    2. 当key!=null的时候,将因哈希碰撞后移的元素重新放置----ThreadLocalMap中使用了后移解决哈希碰撞

源码:

private int expungeStaleEntry(int staleSlot) {Entry[] tab = table;int len = tab.length;// 删除当前元素--value置为null,value引用的对象变成了无引用对象,会被回收;,同样的将数组上该位置的Entry对象置空,原来的Entry对象也会被回收掉;tab[staleSlot].value = null;tab[staleSlot] = null;size--;// Rehash until we encounter nullEntry e;int i;//继续遍历for (i = nextIndex(staleSlot, len);(e = tab[i]) != null;i = nextIndex(i, len)) {ThreadLocal<?> k = e.get();//key为空的时候继续删除if (k == null) {e.value = null;tab[i] = null;size--;} else {//key 不为空的时候rehash,重新计算该key的下标---这里需要注意--rehash的结果可能和原来的值是一样的,因为不能完全保证是否产生过哈希碰撞int h = k.threadLocalHashCode & (len - 1);if (h != i) {tab[i] = null;// Unlike Knuth 6.4 Algorithm R, we must scan until// null because multiple entries could have been stale.while (tab[h] != null)h = nextIndex(h, len);tab[h] = e;}}}return i;}

启发式清理--

        往后遍历,如果找到key为null的过期元素, 则调用探测式清理--启发式清理可以理解为为探测式清理找到一个清理入口,由探测式清理完成具体的清理工作

private boolean cleanSomeSlots(int i, int n) {boolean removed = false;Entry[] tab = table;int len = tab.length;do {i = nextIndex(i, len);Entry e = tab[i];if (e != null && e.refersTo(null)) {n = len;removed = true;i = expungeStaleEntry(i);}} while ( (n >>>= 1) != 0);return removed;}

另外看一下清理工作在哪里被调用--

  1. set(Thread t,T value)->cleabSomeSlots();
  2. set(Thread t,T value)->replaceStaleEntry()->cleanSomeSlots();
  3. get(t)->getEntry()->getEntryAfterMiss()->expungeStaleEntry();
  4. remove()->expungeStaleEntry();
  5. rehash()->expungeStaleEntries->expungeStaleEntry()

上边的调用关系可以看出来基本上我们对ThreadLocal的get,set,remove操作都会触发清理工作,尽量减小了内存泄漏带来的影响---在未做任何操作之前不会主动触发清理,所以在使用ThreadLocal的时候及时调用remove很重要!!!

http://www.ritt.cn/news/15599.html

相关文章:

  • 国外做的比较好的购物网站哪里可以引流到精准客户呢
  • 延庆宜昌网站建设seo优化推广工程师
  • 网站设计 网站开发 西安seo关键词优化举例
  • 上海网站建设建议免费推广引流平台推荐
  • 专门做吃播的网站关键词排名优化怎么做
  • 成都网站开发公司哪家好长春seo网站排名
  • 9420高清在线观看免费大全seo建站
  • 网站建设如何处理病毒木马seo 优化技术难度大吗
  • 网站如何做快排网络热词2023流行语及解释
  • 网页设计难学吗有技术含量吗河北seo网络优化培训
  • 网站更换主机seo的优化原理
  • 南通网站推广优化费用网络推广方案的内容
  • 阳江招聘网丰多采下载班级优化大师
  • 网站建设案列网站建设找哪家公司好
  • 深圳做网站建设开发淘宝seo推广优化
  • 互联网网站建设公司seo优质友链购买
  • 做网站的公司叫什么软件推广链接让别人点击
  • 在哪个网站可以学做淘宝详情关键词排名优化提升培训
  • 做外贸网站格式个人购买链接
  • 做像58这种分类信息网站赚钱吗厦门谷歌seo
  • 邢台网站建设服务搜索引擎推广简称
  • 临清网站推广南昌百度快速排名提升
  • 怎么做视频聊天网站百度经验怎么赚钱
  • 世界杯网站源码下载百度视频排名优化
  • 调研政府网站建设工作seo如何优化网站
  • 网站通过微信支付宝收钱怎么做站长统计 网站统计
  • 怎样修改网站模板南宁网站建设公司排行
  • 山东做网站建设公司电脑培训学校在哪里
  • 网站后台管理系统免费下载南京网络优化培训
  • markdown做网站模板经典模板网站建设