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的使用相关推荐

  1. [书]java并发编程的艺术笔记

    本文属于自己整理的读书笔记,便于回顾.内容绝大部分来自书籍:java并发编程的艺术,版权归原作者所有. 第1章 并发编程的挑战 1.多线程一定比单线程快? 不一定,如同在同时阅读两本书时的来回切换切换 ...

  2. Java并发编程的艺术笔记-Java内存模型

    1.Java内存模型的基础 1.1 并发编程模型的两个关键问题 线程之间如何通信: 通信是指线程之间以何种机制来交换信息 通信机制有两种:共享内存和消息传递 线程之间如何同步: 同步:指程序中用于控制 ...

  3. Java并发编程的艺术笔记(七)——CountDownLatch、CyclicBarrier详解

    一.等待多线程完成的CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作,像加强版的join.(t.join()是等待t线程完成) 例: (1)开启多个线程 ...

  4. Java 并发编程实践 读书笔记四

    组合对象 设计线程安全的类 设计线程安全类的过程应该包括下面3个基本要素: 确定对象状态是由哪些变量构成的 确定限制状态变量的不变约束 制定一个管理并发访问对象状态的策略 对象状态从域讲,如果对象域都 ...

  5. 《Java并发编程的艺术》笔记

    <Java并发编程的艺术>笔记 第1章 并发编程的挑战 1.1 上下文切换 CPU通过时间片分配算法来循环执行任务,任务从保存到再加载的过程就是一次上下文切换. 减少上下文切换的方法有4种 ...

  6. 《Java并发编程的艺术》——线程(笔记)

    文章目录 四.Java并发编程基础 4.1 线程简介 4.1.1 什么是线程 4.1.2 为什么要使用多线程 4.1.3 线程优先级 4.1.4 线程的状态 4.1.5 Daemon线程 4.2 启动 ...

  7. 【Java并发编程的艺术】读书笔记——Java并发编程基础

    学习参考资料:<Java并发编程的艺术> 文章目录 1.线程的几种状态 2.如何安全的终止线程 3.线程间通信(重要) 3.1共享内存 3.2消息传递 1.线程的几种状态 线程在运行的生命 ...

  8. 《Java并发编程的艺术》——Java中的并发工具类、线程池、Execute框架(笔记)

    文章目录 八.Java中的并发工具类 8.1 等待多线程完成的CountDownLatch 8.2 同步屏障CyclicBarrier 8.2.1 CyclicBarrier简介 8.2.2 Cycl ...

  9. 《Java并发编程的艺术》——Java并发的前置知识(笔记)

    文章目录 一.并发编程的挑战 1.1 上下文切换 1.1.1 多线程一定快吗 1.1.2 如何减少上下文的切换 1.2 死锁 死锁发生的条件 预防死锁 避免死锁 1.3 资源限制的挑战 1.3.1 什 ...

  10. Java并发编程的艺术-阅读笔记和思维导图

    最近在坚持每天阅读<<Java并发编程的艺术>>,不但做好笔记(MarkDown格式),还做好思维导图. 如果大家感兴趣,可以可以到码云上阅读笔记和到ProcessOn上阅读思 ...

最新文章

  1. 【百度地图API】建立全国银行位置查询系统(四)——如何利用百度地图的数据生成自己的标注...
  2. 只会python好找工作吗-转行学Python能拿多少钱?二线工作好找吗?
  3. OVS+Docker
  4. 隐私设置错误您的连接不是私密连接_用小米手机的,赶紧将这些保护个人隐私的功能设置起来,安全好用...
  5. 【算法】快速排序/数组第K小的元素
  6. 1/1!-1/3!+1/5!-……
  7. es6 --- 内置的Symbol值
  8. java获取文件夹 路径,Java获取文件的路径
  9. MATLAB 在图像处理和机器视觉的应用举例01 - 官网培训视频笔记(上)-- 图像分割和图像配准
  10. php 升级 源码,通过编译安装升级php(保证原有的扩展不变)
  11. api下载文件三种方式
  12. mac下配置环境变量
  13. 数据结构与算法之图的深度优先遍历(DFS)
  14. ai水墨晕染效果_AI可能是一位优秀的西方画家,但它在中国水墨画中表现良好吗?...
  15. docker下搭建fastfds集群版
  16. Java爬虫——人人网模拟登录
  17. 光彩夺目的30款太阳光线照射Ps笔刷
  18. 百万级电商秒杀架构设计
  19. 操作系统教程(第5版)习题解答
  20. qiankun微前端主子应用通信方案

热门文章

  1. 记一次easywechat企业付款问题
  2. MapGuide open source开发系列教程六: 地图状态与事件(含问题)
  3. Databinding在自定义ViewGroup中如何绑定view
  4. MySQL数据库基础(三)——SQL语言
  5. Android KeyCode 列表
  6. 一个项目的404错误处理页面
  7. RSA加解密VS加签与验签
  8. 用cglib生成的代理类取不到注解的问题
  9. Nagios安装配置教程(二)环境搭建
  10. 面试专题01-一次面试遇到的问题