threedLocal设计原因及详解
ThreedLocal在中文的翻译中应该翻译成:线程局部变量。
1:设计的原因
在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal可以很好的解决多线程操作统一数据造成不一致情况。
public final class ConnectionUtil { private ConnectionUtil() {} private static final ThreadLocal<Connection> conn = new ThreadLocal<>(); public static Connection getConn() {
Connection con = conn.get();
if (con == null) {
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("url", "userName", "password");
conn.set(con);
} catch (ClassNotFoundException | SQLException e) {
// ...
}
}
return con;
} }
这样子,每次连接,都会重新连接一个新的变量副本。
那问题来了?
1、每个线程的变量副本是存储在哪里的?及如何获取和设置线程局部变量?
参考java源码可以看见,
1:每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal。
2:当我们需要改变或者获得该线程内部的变量时,java提供了get()方法
这个获取的过程如下
- 获取当前线程
- 然后获取当前线程中的ThreadLocalMap对象而且,ThreadLocalMap的内部使用一个Entry<ThreadLocal , T>数据结构来向来保存的,
- 判断Entry对象是否为空,如果不为空,则直接获取ThreadLocal中的value,如果为空,则调用setInitialValue()方法对value进行初始化(初始化到ThreadLocal中)
//get()用户获取次当前线程副本值中的线程局部变量。
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //这里面this指的是threadLocal本身
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
对线程局部变量进行初始化:
//对线程局部变量初始化
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
那么如何设置当前线程中的线程局部变量呢?将值设置进ThreadLocal中
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
2:应用场景
当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值的时候最适合使用ThreadLocal。
3:对于内存泄漏情况
由上面的get()和set()方法知道,因为Entry本身内存是继承自WeakReference,这样当ThreadLocal
不再被引用时,因为弱引用机制原因,当jvm发现内存不足时,会自动回收弱引用指向的实例内存,即其线程内部的ThreadLocalMap
会释放其对ThreadLocal
的引用从而让jvm回收ThreadLocal
对象。这里是重点强调下,是回收对ThreadLocal
对象,而非整个Entry
,所以线程变量中的值T
对象还是在内存中存在的,所以内存泄漏的问题还没有完全解决。接着分析JDK的实现,会发现在调用ThreadLocal.get()
或者ThreadLocal.set(T)
时都会定期执行回收无效的Entry
操作。所以这就解决了上述问题中的内存泄漏问题。
参考文件:
https://www.cnblogs.com/jcli/p/talk_about_threadlocal.html
https://blog.csdn.net/u013256816/article/details/51776846
threedLocal设计原因及详解的更多相关文章
- Dubbo架构设计及原理详解
Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合).从服务模型的角度来看,Dubbo采用的是一种非常简单的模 ...
- 最全Kafka 设计与原理详解【2017.9全新】
一.Kafka简介 1.1 背景历史 当今社会各种应用系统诸如商业.社交.搜索.浏览等像信息工厂一样不断的生产出各种信息,在大数据时代,我们面临如下几个挑战: 如何收集这些巨大的信息 如何分析它 如何 ...
- Kafka 设计与原理详解
一.Kafka简介 本文综合了我之前写的kafka相关文章,可作为一个全面了解学习kafka的培训学习资料. 转载请注明出处 : 本文链接 1.1 背景历史 当今社会各种应用系统诸如商业.社交.搜索. ...
- 支付宝小程序PHP全栈开发--前端样式的设计.acss样式详解
关于.acss文件 在视频中已经说过了,小程序的设计思想和原生app的设计思想颇为相似,基本的应用单元为页面.当然对于一个页面来说每一个元素的放置位置在哪儿以及显示成什么样子这个是由样式来决定的.我们 ...
- [转]Kafka 设计与原理详解
一.Kafka简介 本文综合了我之前写的kafka相关文章,可作为一个全面了解学习kafka的培训学习资料. 1 2 1 2 转载请注明出处 : 本文链接 1.1 背景历史 当今社会各种应用系统诸如商 ...
- kafka之二:Kafka 设计与原理详解
一.Kafka简介 本文综合了我之前写的kafka相关文章,可作为一个全面了解学习kafka的培训学习资料. 转载请注明出处 : 本文链接 1.1 背景历史 当今社会各种应用系统诸如商业.社交.搜索. ...
- RBAC用户权限管理数据库设计的图文详解
RBAC(Role-Based Access Control,基于角色的访问控制),就是用户通过角色与权限进行关联.简单地说,一个用户拥有若干角色,每一个角色拥有若干权限.这样,就构造成“用户-角色- ...
- RocketMQ详解(四)核心设计原理
专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...
- RocketMQ详解(一)原理概览
专题目录 RocketMQ详解(一)原理概览 RocketMQ详解(二)安装使用详解 RocketMQ详解(三)启动运行原理 RocketMQ详解(四)核心设计原理 RocketMQ详解(五)总结提高 ...
随机推荐
- 封装7z软件实现批量文件或目录压缩
哈哈,作为一个特别懒的运维人来说 兄弟我写了一个批量压缩文件或目录的小工具,用来批量压缩文件目录 弄一下,然后就不用管他了,后天看结果就好了 操作步骤: 1.选择想做压缩处理的根目录 2.选择你要的功 ...
- python基础训练题2-元组,字典
1,判断值在元组中 >>> a = ( 1, 2, 3, 4, 10 ) >>> 10 in a True >>> ' in a False 2, ...
- APP中内嵌H5页面为什么不能下载?
在APP中内嵌H5页面,若页面上存在下载链接,没有任何反应,为什么呢? 原因是app中内嵌的H5页面是WebView解析的,什么是WebView呢? 在Android手机中内置了一款高性能webkit ...
- 地区picker 各选择器,优劣分析
移动端选择器picker有很多,各大ui组件都有自己的picker,比如light7,HUI,MUI,jqueryUI等等.但是,我发现他们都有各种各样的问题.这次的地区选择,需要地区的省份+市+经纬 ...
- SSM框架下的redis缓存
基本SSM框架搭建:http://www.cnblogs.com/fuchuanzhipan1209/p/6274358.html 配置文件部分: 第一步:加入jar包 pom.xml <!-- ...
- npm install、npm init、npm update、npm uninstall和package.json
npm install 安装本地包 npm install <package_name>:这个命令将在当前目录中创建node_modules目录(如果尚不存在),并将该软件包下载到该目录. ...
- Dynamics 365Online Server-Side OAuth身份认证
在上篇演示了在html页面中通过调用online的OAuth身份验证后再通过web api取10条客户数据并展示,本篇继续讲述如何在server-side程序中调用online的OAuth认证再通过w ...
- ArcGIS Server + ArcGIS Portal 10.5
1.安装IE11 2. 域名需要在C:\Windows\System32\drivers\etc\host文件中添加 127.0.0.1 机器名.域名 win2008.smartmap.com 19 ...
- angularjs -- 页面模板清除
前几天项目在上线过程中,出现了一些新问题.页面在切换时由于前一个页面的模板清理不及时,会造成页面的重叠.导致这个问题的原因是:页面模板缓存,即上一个页面退出时,浏览器没有及时清空上一个页面的模板,导致 ...
- Linux —— Vi 命令介绍
简介 vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器. 这里只是简单地介绍一下它的用法和一小部分指令. 由于对Unix及Linux系统的任何版本,vi编辑 ...