核心源码如下:
四、完整源码
1、核心源码
2、set()
3、getMap()
4、map.set()
5、createMap()
6、get()
7、setInitialValue()
8、initialValue()
9、remove()
10、小结
其实什么东西都怕用心的专研,只要我们理清楚了相关的类关系,ThreadLocal也就没有那么的神秘莫测了。Thread、ThreadLocal、ThreadLocalMap、Entry一句话总结就是:Thread维护了ThreadLocalMap,而ThreadLocalMap里维护了Entry,而Entry里存的是以ThreadLocal为key,传入的值为value的键值对。
五、答疑(面试题)
1、和Synchronized的区别
问:他和线程同步机制(如:Synchronized)提供一样的功能,这个很吊啊。
不是这样的。
同步机制保证:多线程同时操作共享变量并且能正确的输出结果。ThreadLocal把共享变量变成线程私有了,每个线程都有独立的一个变量。
2、存储在jvm的哪个区域
问:线程私有,那么就是说ThreadLocal的实例和他的值是放到栈上咯?
不是这样的,还是在堆内存中。ThreadLocal对象也是对象,是对象就在堆中。只是JVM通过一些技巧将其可见性变成了线程可见。
3、真的只是当前线程可见吗?
问:真的只是当前线程可见吗?
好像不是这样的,通过这个InheritableThreadLocal类就可以实现多个线程访问ThreadLocal的值,但是我确实没有去研究过,广大同行小伙伴如果有人知道,欢迎在评论区留言分享,先谢过啦!
4、会导致内存泄漏吗?
问:会导致内存泄漏么?
首先我们先对这个问题进行2点分析:
1、ThreadLocalMap.Entry的key会内存泄漏吗?2、ThreadLocalMap.Entry的value会内存泄漏吗?话不多说,先看key-value的核心源码:
从继承关系上来看,是继承的弱引用,key是直接交给父类super(key)来处理的,父类就是一个弱引用,因为弱引用会被GC回收的,故此key完全不存在内存泄露问题。
弱引用的特点:如果这个对象只被弱引用关联,没有任何强引用关联,那么这个对象就可以被GC回收掉。弱引用不会阻止GC回收。
由源码可知这里的value是一个强引用,这是不是可能会导致内存泄露呢?
但是我们仔细琢磨一下,这里线程都终止了,不管是强引用还是弱引用都必然会被GC回收的,很简单,因为引用链断掉了。
这样看起来似乎没有问题,但是我们这里忘记了一个重要角色:线程池,在线程池核心线程是不会销毁的,只要创建出来他会反复利用,生命周期不会结束掉,但是key是弱引用会被GC回收掉,value强引用不会回收,所以形成了如下场面:
Thread->ThreadLocalMap->Entry(key为null)->value
由于value和Thread还存在链路关系,还是可达的,所以不会被回收,这样越来越多的垃圾对象产生却无法回收,内存泄漏(OOM)也是迟早的事情。
那怎么办,这么说来ThreadLocal也是不能使用的了?非也。其实作者在开发ThreadLocal的时候就已经想到并给出了解决方案:
ThreadLocal提供了remove()方法,它的作用就是将value移出去的,所以用完后记得调用remove()方法释放资源哟。
5、为什么用Entry数组而不是Entry对象
这个其实主要想考ThreadLocalMap是在Thread里持有的引用。
问:ThreadLocalMap内部的table为什么是数组而不是单个对象呢?
这个其实也很好理解,在实际开发中有时候根据业务需要会new出来好几个ThreadLocal对象,各自承担一份工作。在一个线程里面ThreadLocalMap是同一个,而不是多个,不管new了多少个ThreadLocal对象,为什么呢?因为ThreadLocalMap的引用是在Thread里面的,所以它里面的Entry数组存放的是一个线程里你new出来的多个ThreadLocal对象。
6、你学习的开源框架哪些用到了ThreadLocal
Spring框架。
DateTimeContextHolder
RequestContextHolder
7、ThreadLocal里的对象一定是线程安全的吗
不一定。
假设ThreadLocal.set()进去的值本身就是一个共享变量,如static对象,那么我们在get()的时候获取的还是这个共享对象本身,还是避免不了线程安全问题。
所以大家在使用的时候也一定谨慎!
8、笔试题
问:下面这段程序会输出什么?为什么?
答:
是不是对上面的日志输出信息感到疑惑,为什么输出1后就抛出了空指针异常?
这里输出1是完全没有问题的,但是主线程抛出了空指针这到底是怎么一回事呢?
假设你是如下回答:
要是真是这个回答,那我只能说你根本连ThreadLocal是啥都不知道。非常明显这是子线程和主线程两个线程,子线程中设置为1,根据线程的特点(如果不知道,自行百度,这里不在赘述)主线程肯定拿不到子线程中的数据,上文中的介绍清楚的说明了,ThreadLocal和线程是息息相关的。
文章来源:《电脑编程技巧与维护》 网址: http://www.dnbcjqywh.cn/zonghexinwen/2020/0910/470.html
电脑编程技巧与维护投稿 | 电脑编程技巧与维护编辑部| 电脑编程技巧与维护版面费 | 电脑编程技巧与维护论文发表 | 电脑编程技巧与维护最新目录
Copyright © 2018 《电脑编程技巧与维护》杂志社 版权所有
投稿电话: 投稿邮箱: