转载自:https://www.cnblogs.com/dreamroute/p/5034726.html

ThreadLocal翻译成中文比较准确的叫法应该是:线程局部变量。

  这个玩意有什么用处,或者说为什么要有这么一个东东?先解释一下,在并发编程的时候,成员变量如果不做任何处理其实是线程不安全的,各个线程都在操作同一个变量,显然是不行的,并且我们也知道volatile这个关键字也是不能保证线程安全的。那么在有一种情况之下,我们需要满足这样一个条件:变量是同一个,但是每个线程都使用同一个初始值,也就是使用同一个变量的一个新的副本。这种情况之下ThreadLocal就非常使用,比如说DAO的数据库连接,我们知道DAO是单例的,那么他的属性Connection就不是一个线程安全的变量。而我们每个线程都需要使用他,并且各自使用各自的。这种情况,ThreadLocal就比较好的解决了这个问题。

  我们从源码的角度来分析这个问题。

  首先定义一个ThreadLocal:

public final class ConnectionUtil {

    private ConnectionUtil() {
} private static final ThreadLocal<Connection> conn = new ThreadLocal<>(); public static Connection getConn() {
Connection con = conn.get();
if (con == null) {
try {
Class.forName("com.mysql.jdbc.Driver");
con = DriverManager.getConnection("url", "userName", "password");
conn.set(con);
} catch (ClassNotFoundException | SQLException e) {
// ...
}
}
return con;
} }

  这样子,都是用同一个连接,但是每个连接都是新的,是同一个连接的副本。

  那么实现机制是如何的呢?

  1、每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal。

1
2
3
/* ThreadLocal values pertaining to this thread. This map is maintained
 * by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;

  2、当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocal的value,否则进行初始化,初始化就是将initialValue的值set到ThreadLocal中。

1
2
3
4
5
6
7
8
9
10
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();
}

  3、当我们调用set()方法的时候,很常规,就是将值设置进ThreadLocal中。

  4、总结:当我们调用get方法的时候,其实每个当前线程中都有一个ThreadLocal。每次获取或者设置都是对该ThreadLocal进行的操作,是与其他线程分开的。

  5、应用场景:当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值的时候最适合使用ThreadLocal。

  6、其实说再多也不如看一下源码来得清晰。如果要看源码,其中涉及到一个WeakReference和一个Map,这两个地方需要了解下,这两个东西分别是a.Java的弱引用,也就是GC的时候会销毁该引用所包裹(引用)的对象,这个threadLocal作为key可能被销毁,但是只要我们定义成他的类不卸载,tl这个强引用就始终引用着这个ThreadLocal的,永远不会被gc掉。b.和HashMap差不多。

  事实上,从本质来讲,就是每个线程都维护了一个map,而这个map的key就是threadLocal,而值就是我们set的那个值,每次线程在get的时候,都从自己的变量中取值,既然从自己的变量中取值,那肯定就不存在线程安全问题,总体来讲,ThreadLocal这个变量的状态根本没有发生变化,他仅仅是充当一个key的角色,另外提供给每一个线程一个初始值。如果允许的话,我们自己就能实现一个这样的功能,只不过恰好JDK就已经帮我们做了这个事情。

初识Java ThreadLocal的更多相关文章

  1. 初识Java

    Java是一种简单的.面向对象的.分布式的.解释的.安全的.可移植的.性能优异的多线程语言.它以极强的安全性.平台无关性.硬件结构无关性.语言简洁.面向对象的特点,在网络编程语言中占据了无可比拟的优势 ...

  2. SSH 框架学习之初识Java中的Action、Dao、Service、Model-收藏

    SSH 框架学习之初识Java中的Action.Dao.Service.Model-----------------------------学到就要查,自己动手动脑!!!   基础知识目前不够,有感性 ...

  3. Java 面向对象编程——第一章 初识Java

      第一章    初识Java 1.  什么是Java? Java是一种简单的.面向对象的.分布式的.解释的.安全的.可移植的.性能优异的多线程语言.它以其强安全性.平台无关性.硬件结构无关性.语言简 ...

  4. Personal Learning Path of Java——初识Java

    初识Java 在我个人看来,Java是一门高大上的面向编程语言,这也是Java吸引我的地方.在自学Java之前,我在学校大概学过了一些C语言的知识,在学校学的那点C语言纯属是拿来打基础用的,大概了解了 ...

  5. Java ThreadLocal的使用

    Java中的ThreadLocal类允许我们创建只能被同一个线程读写的变量.因此,如果一段代码含有一个ThreadLocal变量的引用,即使两个线程同时执行这段代码,它们也无法访问到对方的Thread ...

  6. 初识Java作业

    初识Java作业 一.    填空题 Java技术按照用途不同分为三大版本,分别是JavaSE.     javaEE       和JavaMe Java虚拟机就是一个虚拟的用于执行  .class ...

  7. Java学习笔记心得——初识Java

    初识Java 拿到这本厚厚的<Java学习笔记>,翻开目录:Java平台概论.从JDK到TDE.认识对象.封装.继承与多态...看着这些似懂非懂的术语名词,心里怀着些好奇与担忧,就这样我开 ...

  8. Java ThreadLocal 源代码分析

    Java ThreadLocal 之前在写SSM项目的时候使用过一个叫PageHelper的插件 可以自动完成分页而不用手动写SQL limit 用起来大概是这样的 最开始的时候觉得很困惑,因为直接使 ...

  9. 初识Java程序,编写简单代码?

    Dear All: 初识Java程序,编写简单代码? 首先小编在这里说下我们今天编写Java程序使用的是 eclipse 开发工具! 1.下载eclipse 官网地址:http://www.eclip ...

随机推荐

  1. ncodeURIComponent() 函数 vue内容

    ncodeURIComponent() 函数 编辑 encodeURIComponent() 函数[1]  作用:可把字符串作为URI 组件进行编码.其返回值URIstring 的副本,其中的某些字符 ...

  2. JAVA发送HttpClient请求及接收请求结果过程

    1.写一个HttpRequestUtils工具类,包括post请求和get请求 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ...

  3. js脚本代码调试小技巧

    以前写js代码调试代码查看数据是否正确的时候不知道F12(开发者工具),都是alert(xxx)或者console.log(xxx), 现在知道还可以用document.write或者try...ca ...

  4. Linux下基于官方源代码RPM包构建自定义MySQL RPM包

    rpmbuild时不要以root用户执行! 方法一: 1.首先安装rpmbuild #yum install rpm-build gcc gcc-c++ cmake bison ncurses-dev ...

  5. sql server字符串的类型

    sql server字符串分为不同的类型,下面就将为您介绍几个sql server字符串的常见类型,希望对您学习sql server字符串能有所帮助. nchar 此数据类型可存储1~4000个定长U ...

  6. iKcamp|基于Koa2搭建Node.js实战(含视频)☞ 视图Nunjucks

    视频地址:https://www.cctalk.com/v/15114923888328 视图 Nunjucks 彩虹是上帝和人类立的约,上帝不会再用洪水灭人. 客户端和服务端之间相互通信,传递的数据 ...

  7. RabbitMQ 高可用集群搭建

    面向EDA(事件驱动架构)的方式来设计你的消息 AMQP routing key的设计 RabbitMQ cluster搭建 Mirror queue policy设置 两个不错的RabbitMQ p ...

  8. 禁止直接访问ashx页面

      if (context.Request.ServerVariables["HTTP_REFERER"] == null)             {               ...

  9. Windows phone Toast消息推送 学习笔记

    简单介绍: Windows phone平台支持三种形式的推送通知: 1.Tile——也就是在Start屏幕程序平铺图标 2.Toast——创建一个显示在当前屏幕中的Toast弹出窗口 3.Raw——有 ...

  10. Hamburgers

    Hamburgers http://codeforces.com/problemset/problem/371/C time limit per test 1 second memory limit ...