java 线程变量put_Java线程(篇外篇):线程本地变量ThreadLocal
首先说明ThreadLocal存放的值是线程内共享的,线程间互斥的,主要用于线程内共享一些数据,避免通过参数来传递,这样处理后,能够优雅的解决一些实际问题,比如hibernate中的OpenSessionInView,就是使用ThreadLocal保存Session对象,还有我们经常用ThreadLocal存放Connection,代码如:
/**
* 数据库连接管理类
* @author 爽
*
*/
public class ConnectionManager {
/** 线程内共享Connection,ThreadLocal通常是全局的,支持泛型 */
private static ThreadLocal threadLocal = new ThreadLocal();
public static Connection getCurrConnection() {
// 获取当前线程内共享的Connection
Connection conn = threadLocal.get();
try {
// 判断连接是否可用
if(conn == null || conn.isClosed()) {
// 创建新的Connection赋值给conn(略)
// 保存Connection
threadLocal.set(conn);
}
} catch (SQLException e) {
// 异常处理
}
return conn;
}
/**
* 关闭当前数据库连接
*/
public static void close() {
// 获取当前线程内共享的Connection
Connection conn = threadLocal.get();
try {
// 判断是否已经关闭
if(conn != null && !conn.isClosed()) {
// 关闭资源
conn.close();
// 移除Connection
threadLocal.remove();
conn = null;
}
} catch (SQLException e) {
// 异常处理
}
}
}
这样处理的好处:
统一管理Connection;
不需要显示传参Connection,代码更优雅;
降低耦合性。
ThreadLocal有四个方法,分别为:
initialValue
protected T initialValue()
返回此线程局部变量的当前线程的初始值。最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用 get() 方法访问变量的时候。如果线程先于 get 方法调用 set(T) 方法,则不会在线程中再调用 initialValue 方法。
该实现只返回 null;如果程序员希望将线程局部变量初始化为 null 以外的某个值,则必须为 ThreadLocal 创建子类,并重写此方法。通常,将使用匿名内部类。initialValue 的典型实现将调用一个适当的构造方法,并返回新构造的对象。返回:返回此线程局部变量的初始值
get
public T get()
返回此线程局部变量的当前线程副本中的值。如果这是线程第一次调用该方法,则创建并初始化此副本。返回:此线程局部变量的当前线程的值
set
public void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值。许多应用程序不需要这项功能,它们只依赖于 initialValue() 方法来设置线程局部变量的值。参数:value - 存储在此线程局部变量的当前线程副本中的值。
remove
public void remove()
移除此线程局部变量的值。这可能有助于减少线程局部变量的存储需求。如果再次访问此线程局部变量,那么在默认情况下它将拥有其 initialValue。
很多人对ThreadLocal存在一定的误解,说ThreadLocal中有一个全局的Map,set时执行map.put(Thread.currentThread(), value),get和remove时也同理,但SUN的大师们是否是如此实现的,我们只能去看源码了。
set方法:
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
// 获取当前线程对象
Thread t = Thread.currentThread();
// 获取当前线程本地变量Map
ThreadLocalMap map = getMap(t);
// map不为空
if (map != null)
// 存值
map.set(this, value);
else
// 创建一个当前线程本地变量Map
createMap(t, value);
}
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
// 获取当前线程的本地变量Map
return t.threadLocals;
}
这里注意,ThreadLocal中是有一个Map,但这个Map不是我们平时使用的Map,而是ThreadLocalMap,ThreadLocalMap是ThreadLocal的一个内部类,不对外使用的。当使用ThreadLocal存值时,首先是获取到当前线程对象,然后获取到当前线程本地变量Map,最后将当前使用的ThreadLocal和传入的值放到Map中,也就是说ThreadLocalMap中存的值是[ThreadLocal对象, 存放的值],这样做的好处是,每个线程都对应一个本地变量的Map,所以一个线程可以存在多个线程本地变量。
get方法:
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
// 如果值为空,则返回初始值
return setInitialValue();
} 有了之前set方法的分析,get方法也同理,需要说明的是,如果没有进行过set操作,那从ThreadLocalMap中拿到的值就是null,这时get方法会返回初始值,也就是调用initialValue()方法,ThreadLocal中这个方法默认返回null。当我们有需要第一次get时就能得到一个值时,可以继承ThreadLocal,并且覆盖initialValue()方法。
(完)
java 线程变量put_Java线程(篇外篇):线程本地变量ThreadLocal相关推荐
- Java微信公众平台开发--番外篇,对GlobalConstants文件的补充
转自:http://www.cuiyongzhi.com/post/63.html 之前发过一个[微信开发]系列性的文章,也引来了不少朋友观看和点评交流,可能我在写文章时有所疏忽,对部分文件给出的不是 ...
- JAVA基础系列:内部类获取外部类的成员变量
内部类获取外部类的成员变量,使用 外部类类名.this.变量名 的形式获取 public class Outer {public String name = "outer";cla ...
- java concurrentmap原理_Java集合番外篇 -- ConcurrentHashMap底层实现和原理
概述 距离上一次集合篇结束已经过了好久了, 之前说要写一下番外,但是太忙了,总也找不出相对松散的时间,也有点静不下心来,最近花了点时间,于是便有了这篇博客. 在开始之前先介绍一个算法, 这个算法和Co ...
- 【JAVA进阶】java中的集合(番外篇3)- HashMap源码底层数据结构分析
写在前面的话 脑子是个好东西,可惜的是一直没有搞懂脑子的内存删除机制是什么,所以啊,入行多年,零零散散的文章看了无数,却总是学习了很多也忘了很多. 痛定思痛的我决定从今天开始系统的梳理下知识架构,记录 ...
- 【温故而知新】C和C++篇外篇:COleVariant类型
今天在做一个windows平台的小工具顺便熟悉一下windows开发的一些基础知识,在这个过程中,发现了MFC使用了一种数据类型叫做COleVariant类型,感觉比较新鲜,赶忙到网上查一下,做一下记 ...
- Java并发篇_进程线程
一个进程包括由操作系统分配的内存空间,包含一个或多个线程.一个线程不能独立的存在,它必须是进程的一部分.一个进程一直运行,直到所有的非守护线程都结束运行后才能结束. 多线程能满足程序员编写高效率的程序 ...
- Error:(343, 83) java: 从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量
/*** 问题代码(只是为了重现错误,请忽略代码逻辑)*/ @Testpublic void test23(){ArrayList<Book> list = new ArrayList&l ...
- 全局变量 VS 本地变量
文章目录 C全局变量与本地变量 注意事项 Linux Shell全局变量与本地变量 变量释放 C全局变量与本地变量 全局变量 程序内所有函数可以直接调用的变量,对所有函数都是可见的,程序执行完成后释放 ...
- 一文搞定C语言本地变量和全局变量
前言 最近在重新学习C语言,发现了之前本科阶段好多知识都学的不够牢固,现特地重新学习并一同记录下来.那么什么是本地变量,什么又是全局变量呢? 本地变量 本地变量:直白地讲,本地变量就是在函数内部定义地 ...
最新文章
- 【从零学习OpenCV 4】Mat类介绍
- poj3683(2-SAT)
- PowerDesigner165安装婆姐汉花教程
- 计算机应用等级考试1,计算机等级考试一级试题
- 算法--Hash算法及其应用场所
- Android USBCamera投屏 - 利用UVC协议将手机上的画面有线投屏到Android车机的屏幕上
- Windows多用户远程桌面-采用RDP Wrapper Library支持10.0.18363.900、10.0.18362.836、10.0.19041.789之前所有的Windows版本
- 软件工程基础知识--系统测试
- gis怎么改鼠标滚轮缩放_【精华】ArcGIS鼠标滚轮
- 谷歌内核浏览器无法下载文件的解决方法
- python实现自动抢课脚本
- java调用加密机实例_Enigma Java模拟实现恩尼格玛密码机加密解密过程 Develop 238万源代码下载- www.pudn.com...
- Linux: SSH免密登录配置完了不生效
- 升级 Adobe CS5 中的 FlashBuilder 4
- 优质数据平台如何打造?从网易云音乐看内容生态的运营法则
- 虚拟运营商出牌:流量不清零难成杀手锏
- display-table制作表格
- docekrfile
- 如何在你的CSDN 博客中添加广告代码(网赚)
- linux sctp 模块,Linux Kernel SCTP模块多个安全漏洞
热门文章
- oracle获取今天凌晨的时间_oracle查询日期语句有哪些?
- kafka启动_Kafka安装部署——单节点
- python编程书籍1020python编程书籍_从零单排之玩转Python安全编程(II)
- 记录F1分数和召回率
- Java多线程系列(十):源码剖析AQS的实现原理
- 论文浅尝 | 基于属性embeddings的跨图谱实体对齐
- Android官方开发文档Training系列课程中文版:Activity测试之测试环境配置
- Android如何给无法更改继承关系的Activity更换ActionBar(setContentView方法实战)
- 13 计算机组成原理第七章 输入/输出系统 I/O方式 I/O接口
- ConcurrentHashMap源码剖析(1.8版本)