并发编程之ThreadLocal线程本地类
一、ThreadLocal的本质和内部结构
ThreadLocal从字面上翻译就是“线程本地变量”。也就是说这个变量是属于当前线程的,其他线程无法进行访问。
其实本质上ThreadLocal是管理本地线程变量副本这样的一个工具类。用它来维护线程Thread内部的ThreadLocalMap,
通过ThreadLocal可以存取在map中的值。由于这个Map是在各个线程内部,因此用来保证各个线程之间的变量互不干扰。
所以总的来说
ThreadLocal不是用来解决多线程下访问共享变量(同一变量)问题的,并发下共享变量的同步问题要靠锁来保证
ThreadLocal用来保证各个线程下的变量互不影响,因为各个变量是保存在Thread内部的Map
下面展示ThreadLocal的内部结构图
从上面的结构图可以看出:
1、每个线程Thread内部都有个Map集合ThreadLocalMap类型
2、ThreadLocalMap集合内部使用Entry来存储键值对,key为ThreadLocal,value为实际存储的值
3、通过ThreadLocal可以获取当前线程下的存储的值,从而各个线程互不影响
二、ThreadLocal类内部代码分析:
ThreadLocl内部属性与方法如下:
在其主要用到的方法有:
get()、set(T)、remove()、initialValue()
分别是获取当前线程下的变量、设置当前线程下的变量、删除当前线程下的变量、设置初始值
2.1、get方法
步骤如下:
1、获取当前线程变量
2、根据当前线程,获取其中的ThreadLocalMap对象threadLocals
3、假如map存在,将threadLocal作为key获得Entry对象
4、然后判断Entry对象不为空,返回其中的Value
5、假如map为空或者entry为空则设置初始值然后返回,
假如不对其中的initialValue进行重写则返回null
2.2、set方法
步骤如下:
1、获取当前线程变量
2、根据当前线程,获取其中的ThreadLocalMap对象threadLocals
3、假如map不为null,则将threadLocal对象作为key来保存值
4、假如map为null,则创建map然后塞值保存
2.3、remove方法
步骤如下:
1、获取当前线程的ThreadLocalMap属性threadLocals
2、然后传入ThreadLocal对象作为key进行remove操作
三、介绍ThreadLocalMap
总结:
1、可以看出ThreadLocalMap并没有继承Map,而是自己实现逻辑
2、使用内部类Entry来保存值,而Entry是继承弱引用WeakReference,
3、而且可以看出只有Key是弱引用,并且限定key只能为ThreadLocal类
3.1、内存溢出问题
但是由于key是弱引用,可能会出现当ThreadLocal对象没有给强引用时候,
然后在垃圾回收器进行gc时,发现只有弱引用就会进行回收,
这样key只会为null,value的值没办法获取造成内存溢出。
结构图如下:
可以看出,假如ThreadLocal引用变量并没有强引用ThreadLocal对象的时候,当垃圾回收线程检测到的时候就会回收
ThreadLocal对象,这样对应的Entry的key为null。
因此从Thread对象到Object对象这一整引用链中由于key为null,所以没办法获取value。
并且之间存在强引用也没办法进行回收,这样假如线程周期比较长,会形成内存泄露。
相应的开发团队也考虑到这样的问题,在调用get、set、remove方法的时候内部都会调用
当key为null的时候设置value为null,并且设置对应的Entry也为null
且进行遍历所有的key进行上面的清除操作,便于GC进行回收
但无论如何都好,为了防止内存泄露的问题,但使用完ThreadLocal对象后都要调用remove方法
本文作者:hjjay
原文出处:https://www.cnblogs.com/jayhou/p/9811445.html
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。