【总结】ThreadLocal
1.ThreadLocal概念
java.lang.ThreadLoca是一个线程内部的存储类,可以在指定线程内存储数据,数据存储以后,只有指定线程可以得到存储数据(t1.get t1.set)
1.1 synchronized和threadlocal的区别
(1)Synchronized同步机制采用了“以时间换空间”的方式,仅提供一份变量,让不同的线程排队访问
(2)而ThreadLocal采用了“以空间换时间”的方式,每一个线程都提供了一份变量,因此可以同时访问而互不影响。
2.运用场景——转账
转账转入和转出要在同一个事务,service层获得Jdbccollection,然后setautoconmit(false)来使用事务。dao层也要获得一个connection操作数据库。但这两个connection不一致,事务就会失效
1.常规解决
1.传参:将service的collection直接传到dao层
2.加锁:将getconnection方法加锁
2.ThreadLocal解决方案
static ThreadLocal
public static Connection getConnection(){
Connection conn = tl.get();
if(conn == null){
conn = ds.getConnection();
tl.set(conn);
}
return conn;
}
优点:
(1)不用参数传递,避免了代码的耦合
(2)各线程之间数据相互隔离却又具有并发性,避免了同步方式带来的性能损失
3.ThreadLocal内部结构
3.1.结构
每个Thread内部都有一个Map,即ThreadLocalMap;ThreadLocalMap中存放ThreadLocal对象作为key,变量的副本作为value
3.3.threadlocal方法
(1)initialValue:返回当前线程局部变量的初始值
(2)set:设置当前线程绑定的局部变量
(3)get:获取当前线程绑定的局部变量
(4)remove:移除当前线程绑定的局部变量
3.4 ThreadLocalMap基本结构
ThreadLocalMap是ThreadLocal的内部类,没有实现map接口,用独立的方式实现map功能,其内部的Entry也是独立实现的
Entry继承weakReference,也就是key(ThreadLocal)是弱引用,目的是将ThreadLocal对象的生命周期和线程生命周期解绑
同时map解决冲突采用链地址法,ThreadLocalMap使用线性探测法,即当前位置冲突,探测下一个地址是否冲突,不冲突插入
4. 弱引用
4.1.什么是弱引用
正是因为有引用,对象才会在内存中存在。
当对象的引用数量归零后,垃圾回收程序会把对象销毁。
弱引用不会增加对象的引用数量。 引用的目标对象称为所指对象(referent)。 因此我们说,弱引用不会妨碍所指对象被当作垃圾回收。
4.2 ThreadLocalMap的key使用弱引用原因
假如使用强引用,当ThreadLocal不再使用需要回收时,发现某个线程中ThreadLocalMap存在该ThreadLocal的强引用,无法回收,造成内存泄漏。
因此,使用弱引用可以防止长期存在的线程(通常使用了线程池)导致ThreadLocal无法回收造成内存泄漏。
4.3 通常说的ThreadLocal泄露是什么原因
我们注意到Entry对象中,虽然Key(ThreadLocal)是通过弱引用引入的,但是value即变量值本身是通过强引用引入。
这就导致,假如不作任何处理,由于ThreadLocalMap和线程的生命周期是一致的,当线程资源长期不释放,即使ThreadLocal本身由于弱引用机制已经回收掉了,但value还是驻留在线程的ThreadLocalMap的Entry中。即存在key为null,但value却有值的无效Entry。导致内存泄漏。
4.4 怎么避免内存泄露?
1.Threadlocal自身做了一些处理,在每次调用ThreadLocal的get、set、remove方法时都会执行一个方法,该方法检测整个Entry[]表中对key为null的Entry一并擦除,重新调整索引
2.程序员自身,在代码逻辑中使用完ThreadLocal,都要调用remove方法,及时清理

浙公网安备 33010602011771号