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

个人做电子商务网站如何在各大平台推广

个人做电子商务网站,如何在各大平台推广,中山百度网站建设,公众号推广代理文章目录 四种引用的概念Entry的类定义弱引用和内存泄漏如果key使用强引用如果key使用弱引用为什么使用弱引用 hash冲突的解决ThreadLocalMap中的set方法演示垃圾回收get触发GCset触发GC ThreadLocal-内存清理探测式清理(ExpungeStaleEntry)启发式清理&a…

文章目录

  • 四种引用的概念
  • Entry的类定义
  • 弱引用和内存泄漏
    • 如果key使用强引用
    • 如果key使用弱引用
    • 为什么使用弱引用
  • hash冲突的解决
  • ThreadLocalMap中的set方法
  • 演示垃圾回收
    • get触发GC
    • set触发GC
  • ThreadLocal-内存清理
    • 探测式清理(ExpungeStaleEntry)
    • 启发式清理(cleanSomeSlots)
    • ReplaceStaleEntry
    • rehash(全局清理)
  • 学习资料链接:
    • 视频和文档资料1:
    • 视频和文档资料2:

ThreadLocal的set,get方法只是作为一个接口,实质上还是对Thread里面的ThreadLocalMap里面的进行操作
在这里插入图片描述

在这里插入图片描述
jdk1.8之后,每个线程在往ThreadLocal里放值的时候,都会往自己的ThreadLocalMap里存,读也是以ThreadLocal作为引用,在自己的map里找对应的key,从而实现了线程隔离。

Thread t = new Thread();
Map map = getMap(t);//根据线程获取他的threadLocalMap
map.set(new ThreadLocal<xxx>(),new Object());

在这里插入图片描述

四种引用的概念

在这里插入图片描述

Entry的类定义

/** Entry继承WeakReference,并且用ThreadLocal作为key.* 如果key为null(entry.get() == null),意味着key不再被引用,* 因此这时候entry也可以从table中清除。* entry.get()返回的是ThreadLocal类型的key*/
static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
}

弱引用和内存泄漏

强引用(“Strong” Reference),就是我们最常见的普通对象引用,只要还有强引用指向一个对象,就能表明对象还“活着”,垃圾回收器就不会回收这种对象。

弱引用(WeakReference),垃圾回收器一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。

如果key使用强引用

假设ThreadLocalMap中的key使用了强引用,那么会出现内存泄漏吗?

​ 此时ThreadLocal的内存图(实线表示强引用)如下:
在这里插入图片描述
假设在业务代码中使用完ThreadLocal ,threadLocal Ref被回收了。

​ 但是因为threadLocalMap的Entry强引用了threadLocal,造成threadLocal无法被回收。

​ 在没有手动删除这个Entry以及CurrentThread依然运行的前提下,始终有强引用链 threadRef->currentThread->threadLocalMap->entry,Entry就不会被回收(Entry中包括了ThreadLocal实例和value),导致Entry内存泄漏。

​ 也就是说,ThreadLocalMap中的key使用了强引用, 是无法完全避免内存泄漏的。

如果key使用弱引用

在这里插入图片描述
同样假设在业务代码中使用完ThreadLocal ,threadLocal Ref被回收了。

​ 由于ThreadLocalMap只持有ThreadLocal的弱引用,没有任何强引用指向threadlocal实例, 所以threadlocal就可以顺利被gc回收,此时Entry中的key=null。

​ 但是在没有手动删除这个Entry以及CurrentThread依然运行的前提下,也存在有强引用链 threadRef->currentThread->threadLocalMap->entry -> value ,value不会被回收, 而这块value永远不会被访问到了,导致value内存泄漏

​ 也就是说,ThreadLocalMap中的key使用了弱引用, 也有可能内存泄漏。

其实不管是强引用还是弱引用,都会漏内存,只不过是多少的问题,只要忘记remove了,强引用是漏了kv,弱引用漏了v。只能说有点改善,但是不多

为什么使用弱引用

根据刚才的分析, 我们知道了: 无论ThreadLocalMap中的key使用哪种类型引用都无法完全避免内存泄漏,跟使用弱引用没有关系。

​ 要避免内存泄漏有两种方式:

  1. 使用完ThreadLocal,调用其remove方法删除对应的Entry

  2. 使用完ThreadLocal,当前Thread也随之运行结束

相对第一种方式,第二种方式显然更不好控制,特别是使用线程池的时候,线程结束是不会销毁的。

也就是说,只要记得在使用完ThreadLocal及时的调用remove,无论key是强引用还是弱引用都不会有问题。那么为什么key要用弱引用呢?

​ 事实上,在ThreadLocalMap中的set/getEntry方法中,会对key为null(也即是ThreadLocal为null)进行判断,如果为null的话,那么是会对value置为null的。

​ 这就意味着使用完ThreadLocal,CurrentThread依然运行的前提下,就算忘记调用remove方法,弱引用比强引用可以多一层保障:弱引用的ThreadLocal会被回收,对应的value在下一次ThreadLocalMap调用set,get,remove中的任一方法的时候会被清除,从而避免内存泄漏。
在这里插入图片描述

最主要啊,是弱引用会导致key为null,如果key为null了,就说明这个Entry过期了,就要进行垃圾回收了

hash冲突的解决

public void set(T value) {Thread t = Thread.currentThread();ThreadLocal.ThreadLocalMap map = getMap(t);if (map != null)//调用了ThreadLocalMap的set方法map.set(this, value);elsecreateMap(t, value);}ThreadLocal.ThreadLocalMap getMap(Thread t) {return t.threadLocals;}void createMap(Thread t, T firstValue) {//调用了ThreadLocalMap的构造方法t.threadLocals = new ThreadLocal.ThreadLocalMap(this, firstValue);}

这个方法我们刚才分析过, 其作用是设置当前线程绑定的局部变量 :

​ A. 首先获取当前线程,并根据当前线程获取一个Map

​ B. 如果获取的Map不为空,则将参数设置到Map中(当前ThreadLocal的引用作为key)

(这里调用了ThreadLocalMap的set方法)

​ C. 如果Map为空,则给该线程创建 Map,并设置初始值

(这里调用了ThreadLocalMap的构造方法)

这段代码有两个地方分别涉及到ThreadLocalMap的两个方法, 我们接着分析ThreadLocalMap这两个方法。

 /** firstKey : 本ThreadLocal实例(this)* firstValue : 要保存的线程本地变量*/
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {//初始化tabletable = new ThreadLocal.ThreadLocalMap.Entry[INITIAL_CAPACITY];//计算索引(重点代码)int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);//设置值table[i] = new ThreadLocal.ThreadLocalMap.Entry(firstKey, firstValue);size = 1;//设置阈值setThreshold(INITIAL_CAPACITY);}

构造函数首先创建一个长度为16的Entry数组,然后计算出firstKey对应的索引,然后存储到table中,并设置size和threshold。

a. 关于firstKey.threadLocalHashCode

private final int threadLocalHashCode = nextHashCode();private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT);}
//AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减,适合高并发情况下的使用private static AtomicInteger nextHashCode =  new AtomicInteger();//特殊的hash值private static final int HASH_INCREMENT = 0x61c88647;

这里定义了一个AtomicInteger类型,每次获取当前值并加上HASH_INCREMENT,HASH_INCREMENT = 0x61c88647,这个值跟斐波那契数列(黄金分割数)有关,其主要目的就是为了让哈希码能均匀的分布在2的n次方的数组里, 也就是Entry[] table中,这样做可以尽量避免hash冲突。每多一个ThreadLocal,都递增一次HASH_INCREMENT

b. 关于& (INITIAL_CAPACITY - 1)

​ 计算hash的时候里面采用了hashCode & (size - 1)的算法,这相当于取模运算hashCode % size的一个更高效的实现。正是因为这种算法,我们要求size必须是2的整次幂,这也能保证在索引不越界的前提下,使得hash发生冲突的次数减小。

ThreadLocalMap中的set方法

private void set(ThreadLocal<?> key, Object value) {ThreadLocal.ThreadLocalMap.Entry[] tab = table;int len = tab.length;//计算索引(重点代码,刚才分析过了)int i = key.threadLocalHashCode & (len-1);/*** 使用线性探测法查找元素(重点代码)*/for (ThreadLocal.ThreadLocalMap.Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {ThreadLocal<?> k = e.get();//ThreadLocal 对应的 key 存在,直接覆盖之前的值if (k == key) {e.value = value;return;}// key为 null,但是值不为 null,说明之前的 ThreadLocal 对象已经被回收了,// 当前数组中的 Entry 是一个陈旧(stale)的元素if (k == null) {//用新元素替换陈旧的元素,这个方法进行了不少的垃圾清理动作,防止内存泄漏replaceStaleEntry(key, value, i);return;}}//ThreadLocal对应的key不存在并且没有找到陈旧的元素,则在空元素的位置创建一个新的Entry。tab[i] = new Entry(key, value);int sz = ++size;/*** cleanSomeSlots用于清除那些e.get()==null的元素,* 这种数据key关联的对象已经被回收,所以这个Entry(table[index])可以被置null。* 如果没有清除i往后任何entry,并且当前使用量达到了负载因子所定义(长度的2/3),那么进行				 *  rehash(执行一次全表的扫描清理工作)*/if (!cleanSomeSlots(i, sz) && sz >= threshold)rehash();
}/*** 获取环形数组的下一个索引*/private static int nextIndex(int i, int len) {return ((i + 1 < len) ? i + 1 : 0);}

代码执行流程:

  • A. 首先还是根据key计算出索引 i,然后查找i位置上的Entry,

  • B. 若是Entry已经存在并且key等于传入的key,那么这时候直接给这个Entry赋新的value值,

  • C. 若是Entry存在,但是key为null,则调用replaceStaleEntry来更换这个key为空的Entry,

  • D. 不断循环检测,直到遇到为null的地方,这时候要是还没在循环过程中return,那么就在这个null的位置新建一个Entry,并且插入,同时size增加1。

​ 最后调用cleanSomeSlots,清理key为null的Entry,最后返回是否清理了Entry,接下来再判断sz 是否>= thresgold达到了rehash的条件,达到的话就会调用rehash函数执行一次全表的扫描清理。

重点分析 : ThreadLocalMap使用线性探测法来解决哈希冲突的。

​ 该方法一次探测下一个地址,直到有空的地址后插入,若整个空间都找不到空余的地址,则产生溢出。

​ 举个例子,假设当前table长度为16,也就是说如果计算出来key的hash值为14,如果table[14]上已经有值,并且其key与当前key不一致,那么就发生了hash冲突,这个时候将14加1得到15,取table[15]进行判断,这个时候如果还是冲突会回到0,取table[0],以此类推,直到可以插入。

​ 按照上面的描述,可以把Entry[] table看成一个环形数组。

演示垃圾回收

在这里插入图片描述
在这里插入图片描述

get触发GC

get(c)触发GC,恰好是要获取1位置的value,↓↓↓↓
在这里插入图片描述
get(c)之后,原来key为null,value为1,现在key为c,value为null

在这里插入图片描述

set触发GC

在这里插入图片描述
清理完的效果
在这里插入图片描述
针对以上探讨的情况,我们推荐使用remove来清理内存,set,get的方式比较局限

ThreadLocal-内存清理

英文解释:
Expunge:清理,清除
Stale:过期的,失效的

探测式清理(ExpungeStaleEntry)

ExpungeStaleEntry返回下一个Entry为null的位置i
在这里插入图片描述

启发式清理(cleanSomeSlots)

Slot:槽,就是哈希槽的意思
在这里插入图片描述
cleanSomeSlot的调用背景是基于set
在这里插入图片描述

ReplaceStaleEntry

替换旧的无效节点
目的在于基于staleSlot位置,往前找,直到遇到第一个Entry为null的位置,往前找的过程中记录最前面过期Entry的位置slotToExpunge
往前找完了之后往StaleSlot后面找,直到遇到第一个Entry为null的位置,往后找的过程中清理所有过期Entry

在这里插入图片描述
replaceStaleEntry的背景是基于set的调用
在这里插入图片描述

rehash(全局清理)

在这里插入图片描述

学习资料链接:

视频和文档资料1:

通过网盘分享的文件:视频-由浅入深,全面解析ThreadLocal
链接: https://pan.baidu.com/s/1_CtLTXjBlQ1LlqySTmWpwg?pwd=atfs 提取码: atfs
–来自百度网盘超级会员v8的分享

通过网盘分享的文件:资料-ThreadLocal.zip
链接: https://pan.baidu.com/s/15Vz0WJymEtahX8FL1WNqnQ?pwd=pedv 提取码: pedv
–来自百度网盘超级会员v8的分享

【黑马程序员Java基础教程由浅入深全面解析threadlocal】 https://www.bilibili.com/video/BV1N741127FH/?p=12&share_source=copy_web&vd_source=afbacdc02063c57e7a2ef256a4db9d2a

【黑马Java面试八股文教程,大厂面试必会100题之Java并发之ThreadLocal】 https://www.bilibili.com/video/BV1gs4y137dL/?p=2&share_source=copy_web&vd_source=afbacdc02063c57e7a2ef256a4db9d2a

视频和文档资料2:

【透彻理解ThreadLocal,最新最全的面试题及解答】 https://www.bilibili.com/video/BV1L89wYzEc2/?share_source=copy_web&vd_source=afbacdc02063c57e7a2ef256a4db9d2a

通过网盘分享的文件:带你透彻理解Threadlocal.pdf
链接: https://pan.baidu.com/s/1jNfmpwChXb_qtZqk_F7ybg?pwd=xwyp 提取码: xwyp
–来自百度网盘超级会员v8的分享

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

相关文章:

  • 佛山网站开发哪家专业站长统计网站统计
  • 纯静态网站索引怎么做深圳关键词优化公司哪家好
  • 网站运营计划书如何提高百度搜索排名
  • 网站开发技术指标是什么推广价格一般多少
  • php 网站超市谷歌官网首页
  • 上海网站制作计划企业关键词优化专业公司
  • 工商注册信息查询系统湖南网站优化
  • 建设网站有哪些好处济南网站设计
  • 做网站按什么收费专业推广引流团队
  • mc做地图画网站湖北seo关键词排名优化软件
  • 旅游营销网站开发推广方式有哪些
  • 南通专业网站设计制作南京百度提升优化
  • 专业网站建设大型公司中国站长之家域名查询
  • 钻磊二级域名分发重庆seo网络推广
  • 苏州公司建设网站制作最近军事新闻
  • 山西省城乡和建设厅网站小程序源码网
  • 应持续抓好二级网站的建设工作网络营销方案的范文
  • 做一婚恋网站多少钱网络服务中心
  • 企业画册设计制作公司公司优化是什么意思?
  • 唐山做网站那家好企业文化经典句子
  • 萧县建设局网站东莞网站seo技术
  • 单页网站订单系统怎么改邮箱竞价托管的注意事项
  • 深圳金鼎网站建设重庆人社培训网
  • 网站免费正能量软件直播网络营销策划书
  • 域名 空间 建网站在线培训系统平台
  • 做家乡特产的网站天猫店铺申请条件及费用
  • 网站域名自动跳转百度seo收费
  • 网站建设网站优化免费模板
  • 学做粤菜的网站有哪些企业推广方式
  • 新闻资讯网站模板下载关键词怎么优化