ThreadLocal详解

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

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

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

  首先定义一个ThreadLocal:

public class ConnectionUtil {private static ThreadLocal<Connection> tl = new ThreadLocal<Connection>();private static Connection initConn = null;static {try {initConn = DriverManager.getConnection("url, name and password");} catch (SQLException e) {e.printStackTrace();}}public Connection getConn() {Connection c = tl.get();if(null == c) tl.set(initConn);return tl.get();}}

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

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

  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
好文要顶 关注我 收藏该文  

神一样的存在
关注 - 2
粉丝 - 81

+加关注

5
0

« 上一篇:ReferenceQueue的使用
» 下一篇:Java局部变量final

posted @ 2015-12-09 23:46 神一样的存在 阅读(41082) 评论(10) 编辑 收藏
发表评论
#1楼 2016-12-08 16:57 | 刘荦 
henbucuo
支持(0)反对(0)

#2楼 2016-12-20 15:32 | xingoo 
你第一段代码,第一次访问难道不会返回null么?
支持(1)反对(0)

#3楼 2017-01-03 11:50 | 王大壮 
觉得是null吧,作者解答一下
支持(0)反对(0)

#4楼[楼主] 2017-01-03 14:28 | 神一样的存在 
@ 王大壮
改了下哈。
支持(1)反对(0)

#5楼[楼主] 2017-01-03 14:28 | 神一样的存在 
@ xingoo
改了下哈。
支持(1)反对(0)

#6楼 2017-07-20 15:48 | 顽皮的蝙蝠侠 
这样写的话,每次调用getConn()的时候得到的其实是用一个Connection实例,要是某个线程修改了connection实例,这就没有隔离吧
支持(0)反对(0)

#7楼[楼主] 2017-07-20 20:06 | 神一样的存在 
@ 顽皮的蝙蝠侠
不会,是线程绑定的,不会存在并发问题
支持(0)反对(1)

#8楼 2017-08-04 12:37 | Int_Gy 
1
2
3
4
5
6
7
8
private static Connection initConn = null;
    static {
        try {
            initConn = DriverManager.getConnection("url, name and password");
        catch (SQLException e) {
            e.printStackTrace();
        }
    }

1
2
3
4
5
public Connection getConn() {
       Connection c = tl.get();
       if(null == c) tl.set(initConn);
       return tl.get();
   }

@神一样的存在 
你的这段代码,这里应该会导致每个线程实例自己的ThreadLocals也就是一个ThreadLocalMap实例中存储的key和value都是同一个ThreadLocal实例和同一个Connection实例,也就是代码中的t1和initConn。所以每一个线程都对同一个initConn操作了,只不过这个initConn放在每个线程自己独有的threadLocals这个map集合中。所以是没有隔离了。
这是我的理解。

支持(0)反对(0)

#9楼[楼主] 2017-08-04 12:42 | 神一样的存在 
@ Int_Gy
threadlocal的其实简单说来就是为了线程绑定公共资源,其目的就是为了是每个线程能够隔离公共资源,防止并发问题
支持(0)反对(0)

#10楼 2017-09-10 14:34 | Xtrap 
@ 神一样的存在
引用 @Int_Gy
threadlocal的其实简单说来就是为了线程绑定公共资源,其目的就是为了是每个线程能够隔离公共资源,防止并发问题

你的代码确实有问题,没有达到隔离变量的问题。多个线程还是共用一个Connection变量。 
下面是我的测试代码,你可以运行一下。

public class Solution {

private static ThreadLocal<AtomicInteger> tl = new ThreadLocal<AtomicInteger>();
private static AtomicInteger init;
static {
init = new AtomicInteger();
}

public AtomicInteger getConn() {
AtomicInteger c = tl.get();
if(null == c) tl.set(init);
return tl.get();
}

public static void main(String[] args) {

final Solution ss = new Solution();
ss.getConn().set(2);
System.out.println(ss.getConn());

new Thread() {
public void run() {
System.out.println(ss.getConn());
}
}.start();

System.out.println("Hello");
}
}

ThreadLocal详解相关推荐

  1. android Handler机制之ThreadLocal详解

    概述 我们在谈Handler机制的时候,其实也就是谈Handler.Message.Looper.MessageQueue之间的关系,对于其工作原理我们不做详解(Handler机制详解). Messa ...

  2. Java高并发编程详解系列-线程上下文设计模式及ThreadLocal详解

    导语   在之前的分享中提到过一个概念就是线程之间的通信,都知道在线程之间的通信是一件很消耗资源的事情.但是又不得不去做的一件事情.为了保证多线程线程安全就必须进行线程之间的通信,保证每个线程获取到的 ...

  3. 深入浅出多线程编程实战(五)ThreadLocal详解(介绍、使用、原理、应用场景)

    深入浅出多线程编程实战(五)ThreadLocal详解(介绍.使用.原理.应用场景) 文章目录 一.ThreadLocal简介 二.ThreadLocal与Synchronized区别 三.Threa ...

  4. 史上最全ThreadLocal 详解(一)

    目录 一.ThreadLocal简介 二.ThreadLocal与Synchronized的区别 三.ThreadLocal的简单使用 四.ThreadLocal的原理 4.1 ThreadLocal ...

  5. 并发容器之ThreadLocal详解

    文章目录 ThreadLocal的简介 ThreadLocal的实现原理 ThreadLocalMap详解 Entry数据结构 set方法 getEntry方法 remove方法 ThreadLoca ...

  6. Java并发编程:线程封闭和ThreadLocal详解

    什么是线程封闭 当访问共享变量时,往往需要加锁来保证数据同步.一种避免使用同步的方式就是不共享数据.如果仅在单线程中访问数据,就不需要同步了.这种技术称为线程封闭.在Java语言中,提供了一些类库和机 ...

  7. Java中的ThreadLocal详解

    一.ThreadLocal简介 多线程访问同一个共享变量的时候容易出现并发问题,特别是多个线程对一个变量进行写入的时候,为了保证线程安全,一般使用者在访问共享变量的时候需要进行额外的同步措施才能保证线 ...

  8. ThreadLocal 详解

    转自:https://www.cnblogs.com/renyuanwei/p/9635235.html 什么是ThreadLocal 根据JDK文档中的解释:ThreadLocal的作用是提供线程内 ...

  9. 第 5-4 课:ThreadLocal 详解 + 面试题

    什么是 ThreadLocal? ThreadLocal 诞生于 JDK 1.2,用于解决多线程间的数据隔离问题.也就是说 ThreadLocal 会为每一个线程创建一个单独的变量副本. Thread ...

最新文章

  1. sql查两个时间内的数据_如何通过AWR的sql脚本查执行时间、消耗CPU、gets、I/0等的sql?...
  2. Entity Framework Unit Testing problem and solution(转)
  3. Spring boot的@Conditional派生注解
  4. pl/sql过程(一)
  5. 使用 CocoaPods 对公有库开源和私有库组件
  6. linux简单邮件系统,怎样简单搭建一个Linux操作系统邮件服务器
  7. RabbitMQ 的安装----Linux环境
  8. python3 tkinter 实现凯撒密码GUI界面
  9. 汇编语言32位加减乘除运算题
  10. 如何通过OCJP认证考试
  11. 台电x80h安装linux,Teclast 台电 X80h吃上win10,附实际使用体验
  12. 特殊字符的处理 GS RS EOT
  13. 如何学习linux系统
  14. 全面概述将人工智能市场纳入其广泛的数据库
  15. [InnoDB] #CORRUPT LOG RECORD FOUND#[MySQL InnoDB表空损坏,数据库无法启动]#
  16. windows通知栏中显示 微信等应用软件 的通知
  17. 硬件:宽带猫(光猫)的基础知识
  18. 怎么用计算机给u盘加密文件,电脑如何使用bitlocker功能给u盘加密
  19. java 四舍五入保留小数点后两位
  20. python是什么?能干什么

热门文章

  1. 网易视频云:流媒体服务器原理和架构解析
  2. 微信公众号手机端无法打开,但是微信官方调试工具和电脑端可以打开
  3. 世界公认的健康水果大排名!第一名居然是……
  4. krpano 场景切换 通知_krpano 场景转换模式
  5. 检查文件编码是什么格式的
  6. 蓝牙及蓝牙耳机工作原理
  7. DOM是什么意思-前端入门
  8. 揭秘 手机群控 带来的利益
  9. vue项目中 一行文本 文字 根据关键字 改变颜色 改变展示颜色
  10. 三维点云处理-chap1