并发编程之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
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

posted @ 2020-01-13 14:25  hjjay  阅读(1426)  评论(0编辑  收藏  举报