热门标签 | HotTags
当前位置:  开发笔记 > 程序员 > 正文

ThreadLocal部分源码分析和应用场景

结构演进早起JDK版本中,ThreadLocal内部结构是一个Map,线程为key,线程在“线程本地变量”中绑定的值为Value。每一个ThreadLocal实例拥有一个Map实例

结构演进

早起JDK版本中,ThreadLocal内部结构是一个Map,线程为key,线程在“线程本地变量”中绑定的值为Value。每一个ThreadLocal实例拥有一个Map实例。(Key是线程,Value是值)

JDK8中,ThreadLocal内部结构发生了演进,虽然还是Map,但是拥有者变成了Thread实例,每一个Thread实例拥有一个Map实例。Map中的key变为ThreadLocal实例。(Key是ThreadLocal,Value是值)

新版ThreadLocalMap如图:

image

每一个线程在获取本地值时,都会将ThreadLocal实例作为Key从自己拥有的ThreadLocalMap中获取值,别的线程无法访问自己的ThreadLocalMap实例,达到相互隔离的目的。


新版优势(减少了内存消耗)

(1)ThreadLocalMap存储的键值对数量减少。早期版本的数量与线程个数强关联;新版的Key是ThreadLocal实例,会比线程数少。

(2)早期版本ThreadLocalMap拥有者为ThreadLocal,在线程销毁后,ThreadLocalMap仍然存在;新版的ThreadLocalMap拥有者为Thread,Thread实例销毁后,ThreadLocalMap也会随之销毁,减少内存消耗。


Entry的Key需要使用弱引用

为什么不直接使用ThreadLocal实例作为Key呢?

public void funcA() {
ThreadLocal local = new ThreadLocal();
local.set(100);
local.get();
}

当线程执行funA方法时,先新建一个local实例,这是强引用,调用set方法后会在内部新建Entry实例,Key是弱引用包装指向的local实例。当线程执行完A方法后,方法栈帧被销毁,强引用local的值也没有了,但此时线程的ThreadLocalMap对应Entry的Key引用还指向的ThreadLocal实例都不能被GC回收,这将造成内存泄漏问题。


弱引用:对象只能生存到下一次垃圾回收之前。


由于ThreadLocalMap中Key是弱引用,下次GC发生时,可以把那些没有强引用指向的ThreadLocal回收。并且key被回收后,其Entry的key值变为null。后续ThreadLocal的get、set方法被调用时,就会清除这些Key为null的Entry,完成内存释放。


使用state final修饰ThreadLocal对象

ThreadLocal实例作为ThreadLocalMap的Key,针对一个线程内的所有操作是共享的,使用static修饰ThreadLocal节约空间。


应用场景


场景一:线程隔离

这个的典型应用就是“数据库连接独享”。下面的代码来自Hibernate,代码通过ThreadLoacl进行数据库连接(Session)的线程本地化存储。

private static final ThreadLocal threadSession = new ThreadLocal();
public static Session getSession() {
Session s = (Session) threadSession.get();
if(s == null) {
s = getSession();
threadSession.set(s);
}
return s;
}

一个Session代表了一个数据库连接。通过以上代码可以看出,这个Session相当于线程的私有变量,不是所有线程共用的,其他线程是获取不到这个Session的。

一般来说,完成数据库操作之后程序会将Session关闭,节省资源。如果Session为共享的方式,如果某个线程将Session关闭,其他线程在操作Session时就会报错。所以通过ThreadLocal简单实现了数据库连接的安全使用。


Re

《Java高并发核心编程》



推荐阅读
author-avatar
都百美丽人生
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有