ThreadLocal 分析
作者:互联网
1. 先说说他的作用哦,提供线程内的局部变量,不同线程之间不会相互干扰,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的复杂度。
1. 线程并发:在多线程并发场景下
2. 传递数据:可以通过Threadlocal在同一线程,不同组件中传递公共变量
3. 线程隔离:每个线程的变量都是独立的不会相互影响
首先有个例子:
这样线程是比较容易混乱的,会出现当前线程打印其他线程的问题。
ThreadLocal:
1. set(): 将变量绑定到当前线程中
2. get(): 获取当前线程绑定的变量
如果
这样写的话,就保证了每次获取的时候就不会出现问题。 threadlocal 和synchronized 的区别:
synchronized是保证串行执行,多线程的话会排队执行,而threadlocal是线程分别执行,线程与线程之间不影响,也不阻塞,有更高的并发性
他们都用于处理多线程并发访问变量的问题,不过两者处理问你的角度和思路不同。
synchronized加锁,保证同时的时候只有一个线程,访问这个共享资源 体现的是一致性 ThreadLoacal是保证每一个线程都有自己独特的某个变量,体现的是隔离性。
在特定场景下,ThreadLocal 有两个突出的优势:
1. 传递数据: 保存每个线程绑定的数据,在需要的地方可以直接获取,避免参数直接传递带来的代码耦合问题 (避免直接传递,代码耦合)
2. 线程隔离: 各线程之间的数据相互隔离却又具备并发性,避免同步方式带来的性能损失。(避免同步方式带来的性能损失)
转账案例中如何使用ThreadLocal的经典场景,
为了保证service和dao层共用一个connection,那么就要传递connection,如果在service获取连接的话,那么因为这个connection已经逃逸出了该方法,因此会加一个synchronized锁,这样会有两个缺点:1. 加完锁之后,就会导致这段代码会串行执行,影响性能 2. 方法间传递会增加耦合。
此时可以用threadLocal来搞定,每个线程开启一个ThreadLocal 每个线程一个连接,这样就可以做到线程之间的隔离。
接下来介绍ThreadLocal的源码:
首先看下ThreadLocalmap在 1.8之前的内容:
这个是ThreadLocal进行管理的,也就是说多个线程公用一个threadLocal
而1.8 以后,是Thread来维护ThreadLocal的,也就是每个线程都有要给ThreadLocalMap,线程没了ThreadLoaclMap就没了,省空间。
set方法:
1. 首先获取当前线程,并根据当前线程获取一个Map
2. 如果获取的Map不为空,将参数设置到Map中,将当前ThreadLoacl的引用作为key
3. 如果Map为空,则给该线程创建Map,并设置初始值。
initialValue() : 这个方法是ThreadLocal里面的,可以继承之后重写此方法,给threadlocal 设置初始值。
ThreadLocal的操作是围绕ThradLocalMap展开的,那么就可以分析源码:ThreadLocalMap源码
ThreadLocalMap是ThreadLocal的内部类,没有实现Map接口,用独立的方式实现了Map的功能,其内部的Entry也是独立实现。
其存储结构-Entry:在ThreadLocalMap中,也是用Entry来保存K-V结构数据的。不过Entry中的key只能是ThreadLocal对象。
另外,Entry继承WeakReference,也就是key是弱引用,其目的是将ThreadLocal对象生命周期和线程生命周期解绑。
接下来弱引用和内存泄漏问题:
有些程序员在使用ThreadLocal的过程中发现有内存泄漏的情况发生,就猜测这个内存泄漏跟Entry中使用了弱引用的key有关系,这不一定对哦
1. 什么是内存泄漏:
Memory overflow:内存溢出,没有足够的内存提供申请者使用 (没有足够的内存供申请者使用)
Memory leak: 内存泄漏是指程序中已动态分配的对内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃。内存泄漏的堆积最终将导致内存溢出。
2. 弱引用相关概念
强引用: 只要其指向一个对象,那么就能表明对象还活着,垃圾回收器就不会回收这种对象。
弱引用: 只要GC,不管当前内存空间是否足够,都会回收它的内存。
如果说key使用强引用,如果ThreadLocal 这个引用断开了,那么因为key还引用着呢,就导致ThreadLocal回收不了,并且始终有一条强调用链
ThreadRef ---> currentThread ---> Map ---->entry。就导致Entry 不会回收,导致Entry内存泄漏。
那如果是弱引用呢? 当栈中的ThreadLocal Ref使用完了,那么指向ThreadLocal的强引用消失了,那么此时Entry只持有ThreadLocal的弱引用,因此ThreadLocal就可以被GC回收,此时Entry中的key = null
因此在没有手动删除这个Entry以及CurrentThread 依然运行的前提下,也存在有强引用链,value不能被回收,导致value内存泄漏。
那么HashMap冲突是如何解决的呢?
标签:分析,Map,ThreadLocal,线程,内存,Entry,引用 来源: https://www.cnblogs.com/followers/p/16619454.html