Java并发编程的艺术笔记(四)——ThreadLocal的使用
ThreadLocal,即线程变量,是一个以ThreadLocal对象为键、任意对象为值的存储结构。这个结构被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的一个值。目的就是为了让线程能够有自己的变量
可以通过set(T)方法来设置一个值,在当前线程下再通过get()方法获取到原先设置的值。
/**
* 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();
//得到线程的ThredLocalMap
ThreadLocalMap map = getMap(t);
//如果map不为空,则将当前线程的对象作为key,传进来的参数作为value存储
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
看一下ThredLocalMap是什么:
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
.......
看到这是ThreadLocal的一个内部类,使用Entry类进行存储。K是我们的ThredLocal对象。
总结:Thread为每个线程维护了ThreadLocalMap这么一个Map,而ThreadLocalMap的key是LocalThread对象本身,value则是要存储的对象
再来看下get方法:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
拿到这个entry的value。
ThreadLocal本身并不存值,它只是作为ThreadLocalMap的key,来获取value,因此能实现数据隔离。
注意:由于ThreadLocalMap的生命周期和Thread一样长,因此要手动remove掉对应的key,不然会造成内存泄露。
使用场景:
1.管理Connection,尤其是管理数据库连接。
频繁创建和关闭connection是一件很耗时的操作,因此要用到数据库连接池。ThreadLocal可以很好的管理数据库连接,因为它能够实现当前线程的操作都是用同一个Connection,保证了事务!
public class ConnectionUtil {
private static Logger logger = LoggerFactory.getLogger(ConnectionUtil.class);
//数据库连接池
private static BasicDataSource dataSource;
//为不同的线程管理连接
private static ThreadLocal<Connection> local;
static {
BufferedReader br = null;
Properties ipp_prop = new Properties();
try {
String propertiesurl = System.getProperty("user.dir") + "/ipp_parser.properties";
br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(propertiesurl)), "utf-8"));
ipp_prop.load(br);
br.close();
} catch (Exception e1) {
e1.printStackTrace();
}
dataSource = new BasicDataSource();
dataSource.setDriverClassName(ipp_prop.getProperty("db.driver"));
dataSource.setUrl(ipp_prop.getProperty("db.url"));
dataSource.setUsername(ipp_prop.getProperty("db.user"));
dataSource.setPassword(ipp_prop.getProperty("db.password"));
//初始连接
dataSource.setInitialSize(Integer.parseInt(ipp_prop.getProperty("db.initsize")));
//最大连接
dataSource.setMaxTotal(Integer.parseInt(ipp_prop.getProperty("db.maxtotal")));
//最长等待时间
dataSource.setMaxWaitMillis(Integer.parseInt(ipp_prop.getProperty("db.maxwait")));
//最小空闲
dataSource.setMinIdle(Integer.parseInt(ipp_prop.getProperty("db.minidle")));
dataSource.setMaxIdle(Integer.parseInt(ipp_prop.getProperty("db.maxidle")));
//初始化线程池本地
local = new ThreadLocal<>();/**得到连接
* @return
* @throws SQLException
*/
public static Connection getOracleConnection() throws SQLException {
//获取Connection对象
Connection connection = dataSource.getConnection();
//把Connection放进local里
local.set(connection);
logger.info("get oracleConnection");
return connection;
}
public static void closeOracleConnection(){
Connection connection = local.get();
try {
if (connection != null) {
//设置自动提交
connection.setAutoCommit(true);
//连接还给连接池
connection.close();
local.remove();
logger.info("close oracleConnection");
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Java并发编程的艺术笔记(四)——ThreadLocal的使用的更多相关文章
- java并发编程的艺术——第四章总结
第四章并发编程基础 4.1线程简介 4.2启动与终止线程 4.3线程间通信 4.4线程应用实例 java语言是内置对多线程支持的. 为什么使用多线程: 首先线程是操作系统最小的调度单元,多核心.多个线 ...
- 多线程的通信和同步(Java并发编程的艺术--笔记)
1. 线程间的通信机制 线程之间通信机制有两种: 共享内存.消息传递. 2. Java并发 Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式执行,通信的过程对于程序员来说是完全透 ...
- Java并发编程的艺术笔记(五)——Java中的锁
一.Lock接口的几个功能: 显示的获取和释放锁 尝试非阻塞的获取锁 能被中断的获取锁 超时获取锁 使用方式: Lock lock = new ReentrantLock(); lock.lock() ...
- Java并发编程的艺术笔记(七)——CountDownLatch、CyclicBarrier详解
一.等待多线程完成的CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作,像加强版的join.(t.join()是等待t线程完成) 例: (1)开启多个线程 ...
- Java并发编程的艺术笔记(九)——FutureTask详解
FutureTask是一种可以取消的异步的计算任务.它的计算是通过Callable实现的,多用于耗时的计算. 一.FutureTask的三种状态 二.get()和cancel()执行示意 三.使用 一 ...
- Java并发编程的艺术笔记(二)——wait/notify机制
一.概述 一个线程修改了一个对象的值,另一个线程感知到变化从而做出相应的操作.前者是生产者,后者是消费者. 等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B调用 ...
- Java并发编程的艺术· 笔记(1)
目录 1.volatile的原理 2.Synchonized 3.无锁-偏向锁-轻量级锁-重量级锁 4.Java实现原子操作 1.volatile的原理 如何保持可见性: 1)将当前处理器缓存行的数据 ...
- java并发编程的艺术(四)---ConcurrentHashMap原理解析
本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片.视频等原文的内容) 若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cn ...
- Java并发编程的艺术笔记(八)——线程池
一.线程池的主要处理流程 ThreadPoolExecutor执行execute方法分下面4种情况. 1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步需要获 ...
随机推荐
- Python中的xrld模块
一. 什么是xrld模块 python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库. 二. 使用介绍 . empty(空的), number, ...
- 通过设置访问密码查看Tomcat服务器运行状态
安装tomcat 设置访问manager用户名,密码 vim /usr/local/tomcat9/conf/tomcat-users.xml # 设置访问manager用户名,密码 # 在倒数第二行 ...
- 使用curl访问https
在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具.它支持文件的上传和下载,是综合传输工具,但按传统,习惯称url为下载工具.然而在使用cr ...
- 剑指offer-正则表达式匹配-字符串-python****
# -*- coding:utf-8 -*- ''' 题目:请实现一个函数用来匹配包括'.'和'*'的正则表达式. 模式中的字符'.'表示任意一个字符(不包括空字符!),而'*'表示它前面的字符可以出 ...
- golang(5):struct & 链表 & 二叉树 & 接口
struct : 结构体 // 1. 用来自定义复杂数据结构 // 2. struct里面可以包含多个字段(属性) // 3. struct类型可以定义方法,注意和函数的区分 // 4. struct ...
- 算法分析方法之平摊分析(Amotized Analysis)
- 04 Python之while循环/格式化输出/运算符/编码
1. while循环 while 条件: 循环体(break,continue) else: 循环体(break,continue) break:彻底干掉一个循环,直接跳出. continue:停止当 ...
- new Date,Date.parse()传值
获取时间: 获取1997年10月1号日期 new Date: 当使用 - 拼接年月日时将会使用UTC时区解析参数,会比北京时间快八小时. 当时用 / 拼接年月日时会使用北京的时区去解析参数,取到的是北 ...
- 访问接口错误,com.netflix.client.ClientException: Load balancer does not have available server for client: panfeng-item-service
com.netflix.client.ClientException: Load balancer does not have available server for client: panfeng ...
- ThinkPHP依赖注入
D:\wamp64\www\thinkphp5.1\tp5.1\application\index\controller\Demo1.php文件 <?php namespace app\inde ...