可以想像,如果一个对象的可变的变量被多个线程访问时,必然是不安全的。

  在单线程应用可能会维持一个全局的数据库连接,并在程序启动时初始化这个连接对象,从而避免在调用每个方法时都传递一个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封闭的变量elsecreateMap(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);elsecreateMap(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

转载于:https://www.cnblogs.com/yvkm/p/10664109.html

ThreadLocal的意义和实现相关推荐

  1. 用了三年 ThreadLocal 今天才弄明白其中的道理

    来自:码匠笔记 ThreadLocal 对于大家并不陌生,每个人应该多少都用过,或者接触过,那么你真的了解她吗?我也是今天才揭开了她的神秘面纱. 看完这篇文章你将 GET 如下知识点: 什么是 Thr ...

  2. Multipart自定义资源限制文件大小限制设计——aop切面怎么才能切入Multipart的文件大小拦截?

    Multipart自定义资源限制文件大小限制设计--aop切面怎么才能切入Multipart的文件大小拦截? author:陈镇坤27 创建时间:2022年1月23日 创作不易,转载请注明来源 摘要: ...

  3. ThreadLocal为什么要使用弱引用和内存泄露问题

    在threadlocal的生命周期中,都存在这些引用. 看下图: 实线代表强引用,虚线代表弱引用. 下面来看两个问题: 1为什么要使用弱引用 2为什么会出现内存泄露问题 - 为什么要使用弱引用 - 每 ...

  4. 面试:说说你对 ThreadLocal 的认识?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! ThreadLocal的原理和实现 ThreadLoal ...

  5. 并发基础(十) 线程局部副本ThreadLocal之正解

    什么是ThreadLocal ThreadLocal是线程局部变量,所谓的线程局部变量,就是仅仅只能被本线程访问,不能在线程之间进行共享访问的变量.在各个Java web的各种框架中ThreadLoc ...

  6. Java8 ThreadLocal 源码分析

    可参考文章: Java8 IdentityhashMap 源码分析 IdentityhashMap 与 ThreadLocalMap 一样都是采用线性探测法解决哈希冲突,有兴趣的可以先了解下 Iden ...

  7. j2ee servlet 和 threadlocal ,synchronized 与 web容器

    在传统的Web开发中,我们处理Http请求最常用的方式是通过实现Servlet对象来进行Http请求的响应.Servlet是J2EE的重要标准之一,规定了Java如何响应Http请求的规范.通过Htt ...

  8. ThreadLocal以及增强

    多线程的本质就是增加任务的并发,提高效率.但是又要控制任务不错乱,可以通过锁来控制资源的访问. 除了控制资源的访问外,我们可以通过增加资源来保证所有对象的线程安全.比如100个人填写个人信息表,如果只 ...

  9. 多线程与高并发(五):强软弱虚四种引用以及ThreadLocal的原理与源码

    上节回顾 AQS(CLH的变种) 因为新加进来的节点要查看前面的节点的状态,所以使用的是双向链表. AQS的底层是 CAS + Volitile,用CAS替代了锁整个链表的操作. 公平锁:上来先排队 ...

最新文章

  1. linux 快速删除大量/大文件
  2. Android悬浮按钮锚点位置,Android 滑动定位+吸附悬停效果实现
  3. 前端wxml取后台js变量值_这些鲜为人知的前端冷知识,你都GET了吗?
  4. 深度学习:什么是自编码器(Autoencoder)
  5. 小结SpringMVC(二)
  6. AutoCAD2007专业版
  7. 体脂的计算Java_简单测试体脂率的两种经验公式
  8. CodeForces 595A Vitaly and Night
  9. 计算机中单位换算tb,bit Byte KB MB GB TB 单位换算
  10. 用计算机玩吃鸡,W10电脑系统玩吃鸡游戏会卡顿怎么办
  11. 后端开发面试自我介绍_java工程师面试自我介绍范文
  12. 软件测试工作中有哪些常用的工具?
  13. Acdream 1729 Crime
  14. 介绍一款web端的截图工具
  15. php随机缩略图,实现随机缩略图的简单思路和phpcms随机缩略图两种方法
  16. 没有链克口袋,但我一样玩游戏掘金
  17. JavaScript 04 — Array Cardio Day 1
  18. Apple Pay入华一年:称雄美国在华败北
  19. Macbooster8最新版Mac清理工具
  20. KDB_Database_Link 使用介绍

热门文章

  1. 快速融入新团队的一点个人体会
  2. 「 每日一练,快乐水题 」693. 交替位二进制数
  3. Docker搭建Nacos1.3+Seata1.4+MySQL8分布式事务(服务端)
  4. Nginx反向代理负载均衡时,验证码不正确
  5. C语言再学习 -- dmesg 命令
  6. wordpress 独立 php,wordpress怎么把所有文章分类单独在一个页面显示
  7. 【附代码】如何在私有链上编写、部署与以太坊进行交互的智能合约
  8. C语言结构体里的成员数组和指针
  9. 应用层的AIDL用法(原)
  10. Android面试题详细整理系列(三)