ThreadLocal的意义和实现
可以想像,如果一个对象的可变的变量被多个线程访问时,必然是不安全的。
在单线程应用可能会维持一个全局的数据库连接,并在程序启动时初始化这个连接对象,从而避免在调用每个方法时都传递一个Connection对象。ThreadUnsafe类就是这样做的:
public class ThreadUnsafe {
private static Connection connection = DriverManager.getConnection(DB_URL); public void Connection getConnection{ /* 在多线程应用中,connection 在被多个线程访问 */
return connection;
}
}
但是JDBC连接对象不一定是线程安全的,在多个线程访问到Connection时,就可能出现安全问题。为了解决这个问题,ThreadLocal类提供了安全的做法。
通过将JDBC的Connection对象封装在ThreadLocal对象中,当每个线程访问需要Connection对象时,ThreadLocal对象返回的是一个副本。
public class ThreadUnsafe {
private static ThreadLocal<Connection> connectionHodler = new ThreadLocal<>{
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
} public void Connection getConnection{ /* 即使多个线程可以访问,依然安全 */
return connectionHolder.get();
}
}
ThreadLocal是如何实现这种功能?
首先,在Thread类中有一个threadLocals的实例变量,这是一个Map,保存了与线程相关的ThreadLocal对象封装的变量。
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
当线程初次调用ThreadLocal对象的get方法时,就会调用initialValue()来获取初始值。
/**
* 返回ThreadLocal封装的对象。*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) { /* 首次调用map为null */
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue(); /* 首次调用的返回值 */
} /**
* 初始化封装在ThreadLocal中对象的值。*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value); //为什么键值是ThreadLocal对象?,因为一个线程对象可能有使用多个ThreadLocal封闭的变量
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);
} public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
} /**
* 创建一个Map,用于保存ThreadLocal和其封装的对象。*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
注意:ThreadLocalMap在ThreadLocal类中声明,却是在Thread类中使用的,原因在于,当线程结束时,这些特定于线程的值保存在Thread对象中,当线程终止后,这些值会作为垃圾回收。
ThreadLocal类实现的是一种线程封闭技术。将变量封闭在单线程中,从而避免同步。
参考: 《Java Concurrency in Practice》 P35&P37
ThreadLocal的意义和实现的更多相关文章
- 解析ThreadLocal
如果定义了一个单实例的java bean,它有若干属性,但是有一个属性不是线程安全的,比如说HashMap.并且碰巧你并不需要在不同的线程中共享这个属性,也就是说这个属性不存在跨线程的意义.那么不推荐 ...
- ThreadLocal实现方式&使用介绍—无锁化线程封闭
原文出处: xieyu_zy 虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以 ...
- 切换数据库+ThreadLocal+AbstractRoutingDataSource 一
最近项目用的数据库要整合成一个,所以把多源数据库切换的写法要清除掉.所以以下记载了多远数据库切换的用法及个人对源码的理解. 框架:Spring+mybatis+vertx,(多源数据库切换的用法不涉及 ...
- 【Java】ThreadLocal细节分析
ThreadLocal通过中文解释就是线程本地变量,是线程的一个局部变量.根据哲学家黑格尔“的存在即合理”的说法,ThreadLocal的出现肯定是有它的意义,它的出现也是因为多线程的一个产物.Thr ...
- ThreadLocal用法和实现原理
如果你定义了一个单实例的java bean,它有若干属性,但是有一个属性不是线程安全的,比如说HashMap.并且碰巧你并不需要在不同的线程中共享这个属性,也就是说这个属性不存在跨线程的意义.那么你不 ...
- ThreadLocal解析
ThreadLocal 如果定义了一个单实例的java bean,它有若干属性,但是有一个属性不是线程安全的,比如说HashMap.并且碰巧你并不需要在不同的线程中共享这个属性,也就是说这个属性不存在 ...
- 深入ThreadLocal之三(ThreadLocal可能引起的内存泄露)
threadlocal里面使用了一个存在弱引用的map,当释放掉threadlocal的强引用以后,map里面的value却没有被回收.而这块value永远不会被访问到了. 所以存在着内存泄露. 最好 ...
- 【转载】Java中如何写一段内存泄露的程序 & ThreadLocal 介绍和使用
可以参考这段文章: link A1:通过以下步骤可以很容易产生内存泄露(程序代码不能访问到某些对象,但是它们仍然保存在内存中): 上文中提到了使用ThreadLocal造成了内存泄露,但是写的不清不楚 ...
- ThreadLocal实现方式&使用介绍---无锁化线程封闭
虽然现在可以说很多程序员会用ThreadLocal,但是我相信大多数程序员还不知道ThreadLocal,而使用ThreadLocal的程序员大多只是知道其然而不知其所以然,因此,使用ThreadLo ...
随机推荐
- 队列->队列的应用(银行业务模拟)
文字描述 示意图 代码实现 // // Created by Zhenjie Yu on 2019-04-13. // #include <stdio.h> #include <st ...
- Linux_磁盘分布_以及分区
运用 Xshell 工具链接到你的服务器 1. Fdisk -l 这是查看磁盘挂载列表情况 2. Fdisk /dev/vdc 这是分区这个磁盘 m 是查看信息 ...
- LeetCode 705 Design HashSet 解题报告
题目要求 Design a HashSet without using any built-in hash table libraries. To be specific, your design s ...
- js之history
浏览历史记录window.history,不会刷新页面内容,只会更改历史记录,用location.href 才会刷新 1. history.pushState() & history.repl ...
- HotSpot设计原理与实现:一、初识HotSpot
一.HotSpot内核模块组成和功能框架 1.HotSpot内核模块图 (1)Prims模块: (2)Service模块: (3)Runtime模块: 二.虚拟机生命周期(JVM初始化过程) 1.虚拟 ...
- 小程序报错 TLS 版本必须大于等于 1.2
https://www.cnblogs.com/phpper/p/6866036.html 服务器是windows 2008 server 环境是IIS7SSL是申请用的阿里免费.微信小程序发现wx. ...
- .Net开发常用工具插件
多功能工具 Notepad++/Sublime Text 3/VS code Web请求工具 Postman .Net开发工具 Microsoft Visual Studio以及代码规范审查插件Sty ...
- BeautifulSoup库的使用
1.简介 BeautifulSoup库也是一个HTML/XML的解析器,其使用起来很简单,但是其实解析网站用xpath和re已经足矣,这个库其实很少用到.因为其占用内存资源还是比xpath更高. '' ...
- 干了这杯Java之集合概览
Java集合框架支持两种类型容器: 一种是为了存储一个元素的合集,为Collection 一种是为了存储键/值对,为Mapping Collection包含 Set存储不重复的元素 List存储一个有 ...
- U盘安装Windows原版系统(安装方式有很多,我讲我的安装方式)
我陈某人,也是安装过至少200部台式或笔记本的人物. 低调,低调,开个玩笑~ 安装方式有很多,我讲我的安装方式,欢迎收藏. 1.下载准备文件下载.iso原版系统镜像文件http://msdn.itel ...