ThreadLocal 学习
为线程提供一个线程私有的变量副本
ThreadLocal提供的只是一个浅拷贝,如果变量是一个引用类型,那么就要考虑它内部的状态是否会被改变,想要解决这个问题可以通过重写ThreadLocal的initialValue()函数来自己实现深拷贝
和Synchronized 的区别: 多线程一个变量
ThreadLocal:一个变量不被多个线程共享,用空间换时间
底层:
ThreadLocal中含有一个叫做ThreadLocalMap的内部类,用来存储变量副本的。key 为 ThreadLocal对象而且还使用了WeakReference,ThreadLocalMap
get方法:
通过当前线程Thread 获取线程的ThreadLocalMap(这个是线程的实例变量 存放私有数据的),如果当前线程的map为null 则setInitialValue()进行初始化 ,如果不为空 ,去取数 用当前threadLocal的变量作为key( map.getEntry(this) ) 如果没有对应的数 则把当前的threadLocal变量 加到map里面
setInitialValue:
如果线程的map为null 则CreateMap,如果不为空 则把当前的ThreadLocal 变量 对象 放到map里面
第一次创建 和新增的时候的value 默认为null
(我们可以通过重写这个函数来返回我们想要在ThreadLocal中维护的变量)
问题:值 是怎么存进去的
值是set进去的:
1 | private static final ThreadLocal |
内存泄漏:
如果threadLocal变量设置为null,map中会放key为null的数,因为map在线程中 所以只要不结束 就会泄漏,
解决方法:ThreadLocalMap中的getEntry()、set()和remove()函数都会清理key为null的Entry
为什么是使用弱引用:
强引用key:ThreadLocal被设置为null,由于ThreadLocalMap持有ThreadLocal的强引用,如果不手动删除,那么ThreadLocal将不会回收,产生内存泄漏。
弱引用key:ThreadLocal被设置为null,由于ThreadLocalMap持有ThreadLocal的弱引用,即便不手动删除,ThreadLocal仍会被回收,ThreadLocalMap在之后调用set()、getEntry()和remove()函数时会清除所有key为null的Entry。
为了安全地使用ThreadLocal,必须要像每次使用完锁就解锁一样,在每次使用完ThreadLocal后都要调用remove()来清理无用的Entry。
1 | public T get() { |