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();//得到线程的ThredLocalMapThreadLocalMap map = getMap(t);//如果map不为空,则将当前线程的对象作为key,传进来的参数作为value存储if (map != null)map.set(this, value);elsecreateMap(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();}} }
转载于:https://www.cnblogs.com/lingluo2017/p/10239081.html
Java并发编程的艺术笔记(四)——ThreadLocal的使用相关推荐
- [书]java并发编程的艺术笔记
本文属于自己整理的读书笔记,便于回顾.内容绝大部分来自书籍:java并发编程的艺术,版权归原作者所有. 第1章 并发编程的挑战 1.多线程一定比单线程快? 不一定,如同在同时阅读两本书时的来回切换切换 ...
- Java并发编程的艺术笔记-Java内存模型
1.Java内存模型的基础 1.1 并发编程模型的两个关键问题 线程之间如何通信: 通信是指线程之间以何种机制来交换信息 通信机制有两种:共享内存和消息传递 线程之间如何同步: 同步:指程序中用于控制 ...
- Java并发编程的艺术笔记(七)——CountDownLatch、CyclicBarrier详解
一.等待多线程完成的CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作,像加强版的join.(t.join()是等待t线程完成) 例: (1)开启多个线程 ...
- Java 并发编程实践 读书笔记四
组合对象 设计线程安全的类 设计线程安全类的过程应该包括下面3个基本要素: 确定对象状态是由哪些变量构成的 确定限制状态变量的不变约束 制定一个管理并发访问对象状态的策略 对象状态从域讲,如果对象域都 ...
- 《Java并发编程的艺术》笔记
<Java并发编程的艺术>笔记 第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种 ...
- 《Java并发编程的艺术》——线程(笔记)
文章目录 四.Java并发编程基础 4.1 线程简介 4.1.1 什么是线程 4.1.2 为什么要使用多线程 4.1.3 线程优先级 4.1.4 线程的状态 4.1.5 Daemon线程 4.2 启动 ...
- 【Java并发编程的艺术】读书笔记——Java并发编程基础
学习参考资料:<Java并发编程的艺术> 文章目录 1.线程的几种状态 2.如何安全的终止线程 3.线程间通信(重要) 3.1共享内存 3.2消息传递 1.线程的几种状态 线程在运行的生命 ...
- 《Java并发编程的艺术》——Java中的并发工具类、线程池、Execute框架(笔记)
文章目录 八.Java中的并发工具类 8.1 等待多线程完成的CountDownLatch 8.2 同步屏障CyclicBarrier 8.2.1 CyclicBarrier简介 8.2.2 Cycl ...
- 《Java并发编程的艺术》——Java并发的前置知识(笔记)
文章目录 一.并发编程的挑战 1.1 上下文切换 1.1.1 多线程一定快吗 1.1.2 如何减少上下文的切换 1.2 死锁 死锁发生的条件 预防死锁 避免死锁 1.3 资源限制的挑战 1.3.1 什 ...
- Java并发编程的艺术-阅读笔记和思维导图
最近在坚持每天阅读<<Java并发编程的艺术>>,不但做好笔记(MarkDown格式),还做好思维导图. 如果大家感兴趣,可以可以到码云上阅读笔记和到ProcessOn上阅读思 ...
最新文章
- 【百度地图API】建立全国银行位置查询系统(四)——如何利用百度地图的数据生成自己的标注...
- 只会python好找工作吗-转行学Python能拿多少钱?二线工作好找吗?
- OVS+Docker
- 隐私设置错误您的连接不是私密连接_用小米手机的,赶紧将这些保护个人隐私的功能设置起来,安全好用...
- 【算法】快速排序/数组第K小的元素
- 1/1!-1/3!+1/5!-……
- es6 --- 内置的Symbol值
- java获取文件夹 路径,Java获取文件的路径
- MATLAB 在图像处理和机器视觉的应用举例01 - 官网培训视频笔记(上)-- 图像分割和图像配准
- php 升级 源码,通过编译安装升级php(保证原有的扩展不变)
- api下载文件三种方式
- mac下配置环境变量
- 数据结构与算法之图的深度优先遍历(DFS)
- ai水墨晕染效果_AI可能是一位优秀的西方画家,但它在中国水墨画中表现良好吗?...
- docker下搭建fastfds集群版
- Java爬虫——人人网模拟登录
- 光彩夺目的30款太阳光线照射Ps笔刷
- 百万级电商秒杀架构设计
- 操作系统教程(第5版)习题解答
- qiankun微前端主子应用通信方案