API
ThreadLocal初始化
java8新初始化方法 静态的
自己调用自己方法 不会影响到他人
使用例子:
☆注意点
所以必须remove();
错误案例:
没有清空ThreadLocal
正常应该都是0 和 1
每次用完情况 就算复用也不会有影响
ThreadLocal、ThreadLocalMap、Thread三者关系
ThreadLocal是一个特殊的类,它没有父类。它是一个线程本地类,只在当前线程范围内可用,并且线程结束后就会被销毁。因此,ThreadLocal不是内部类,也不是外部类。
ThreadLocalMap是Thread的成员变量
源码分析
ThreadLocal Get()方法
先拿到当前线程,
getMap():实际就是拿到当前线程的threadLocals成员变量(ThreadLocalMap类型)
实际也就是ThreadLocal里的ThreadLocalMap
根据传入当前ThreadLocal对象,拿到Entry,拿到Entry的value 返回去
---------------------------------------------------------------------------------
如果ThreadLocalMap为null 则调用setInitialValue设置初始值
如果不设置初始值,则返回null
容易空指针异常
如果map为null,创建map
实际上就是new了一个ThreadLocalMap key为当前ThreadLocal和value为传进去的值
再进去 new了一个Entry 容量为16,和HashMap有异曲同工之妙
Get()方法结束
=================================================================================
Set()方法
首先拿到当前线程,取出当前线程的ThreadLocalMap,如果为null
如果ThreadLocalMap为null,进行初始化
K为当前ThreadLocal,V为传进去的值
如果不为null,直接set,如果有旧值就替换
ThreadLocalMap:
什么是内存泄露?
当不再使用的对象或者变量占用的内存不能被回收,就是内存泄露。
强引用、软引用、弱引用、虚引用
强引用
示例:
显示的赋值为null,才会被gc回收
软引用
把虚拟机内存调小到10MB,这时候定义个20Mb对象,显然内存不够了
软引用使用场景,只有内存不够时才会被回收
弱引用
只要运行gc,垃圾回收,不管内存是否够用 都会被回收
虚引用
执行gc后,虚引用(PhantomReference)所引用的对象不会被立即回收。
PhantomReference是一种更弱的引用类型,它仅用于跟踪对象是否已经被垃圾回收器标记为可终止,并且在垃圾回收器回收该对象时,将该对象添加到引用队列中。当垃圾回收器准备回收一个对象时,它会将该对象标记为可终止,并将其与其虚引用相关联。在垃圾回收器将该对象回收之前,虚引用所引用的对象不会被立即回收。当垃圾回收器回收该对象时,它会将该对象添加到与其关联的引用队列中。
程序可以通过检查引用队列中是否有元素来确定对象是否已经被回收。因此,虚引用并不能保证被回收,只能用来跟踪对象是否已经被回收。
当虚引用被回收时,通过检查引用队列来检查是否回收
---------------------------------------------------------------------------------
ThreadLocalMap是ThreadLocal的静态内部类
为什么ThreadLocalMap采用的是弱引用?
一般new出来的,不加特别说明就是强引用。
相当于人没了,身份证也要被拿掉,注销,不可能还留在这个世界上,否则越积越多。
在多线程场景下,线程会被复用,相当于人没了,但身份证还在
所以使用ThreadLocal时一定要记得手动remove();
expungeStaleEntry
清除废弃过期的Entr,也就是key为null,但Value值还在的Entry
e.get()会得到当前的引用
所以 如果key为null,value也会置为null
remove():
寻找脏Entry,把key=null的Entry删除。
首先e.clear会把引用置为null,其次调用expungeStaleEntry将key为null的value也置为null