在java开源项目的代码中看到一个类里ThreadLocal的属性:
private static ThreadLocal<Boolean> clientMode = new ThreadLocal<>();

印象中在看书的时候见到过ThreadLocal,但突然就想不起它的用处了。。心里一惊感觉当时书白看了。于是马上网上查了查。

 
原来它的意思是线程的本地变量,ThreadLocal更像是一个线程变量访问的工具类。
 
那为什么要用这种方法呢?
翻看了《Java并发编程实践》,看到这么一个说法:线程本地变量通常用于防止可变单例或者全局变量的设计中,出现不正确的共享。
 
感觉这个看着很生硬啊。书中也举了例子,是JDBC的Connection的应用。Connection对于单线程的程序中,一般会启动时就创建好,这样就不用每次都创建对象啦。但是换到多线程环境下就不行了,因为JDBC规范并没有要求Connection是线程安全的。那么如果要解决就可以使用ThreadLocal。使用ThreadLocal可以在每个线程中创建一个Connection对象,这样就满足线程安全要求了。
 
这里比较好奇的是ThreadLocal是如何做到这些的呢?
 
ThreadLocal的实现
打开源代码,ThreadLocal是个泛型类,里面也并不复杂,看到的构造函数也是什么也没有做。ThreadLocal中比较常用的方法主要是set和get。最主要的奥秘便是下面这几行代码:
private final int threadLocalHashCode = nextHashCode();

    /**
* The next hash code to be given out. Updated atomically. Starts at
* zero.
*/
private static AtomicInteger nextHashCode =
new AtomicInteger(); /**
* The difference between successively generated hash codes - turns
* implicit sequential thread-local IDs into near-optimally spread
* multiplicative hash values for power-of-two-sized tables.
*/
private static final int HASH_INCREMENT = 0x61c88647; /**
* Returns the next hash code.
*/
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}

threadLocalHashCode这个变量会随着ThreadLocal构造时创建,而初始化它的是一个nextHashCode()方法。从nextHashCode方法便知道是对一个整形变量nextHashCode进行了一个加法运算,而是固定的增加HASH_INCREMENT大小。

 
这样做是什么意思呢?其实就是每次创建ThreadLocal时都产生一次新的hash值,就是让每次的对象不一样。那么有何用处?
 
再看看set方法,因为这个方法是ThreadLocal将变量设置到线程中的方法:
/**
* 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();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

可以看到方法的执行过程:

1、获得当前线程的实例
2、然后从线程里获取ThreadLocalMap对象,这就是线程里存本地变量的地方
3、如果map不为空则将value写入到map中,而key就是当前ThreadLocal的对象
4、如果为null,刚创建map,当然同样会将value写入map中,key同样是ThreadLocal的对象
 
这样就理解了,其实ThreadLocal每次产生一个新的对象,以此来保证每个线程都针对一个ThreadLocal对象。然后将数据通过set方法向线程中的threadLocals写入值,以此来保证线程安全。当然在写入的value必须不是一个共享对象,否则也是无法保证一定线程安全的。
 
 
引用:
《java并发编程实践》
正确理解ThreadLocal:http://www.iteye.com/topic/103804
 
 
 
注:此文章为原创,欢迎转载,请在文章页面明显位置给出此文链接!
若您觉得这篇文章还不错请点击下右下角的推荐,非常感谢!
http://www.cnblogs.com/5207

ThreadLocal简单理解的更多相关文章

  1. ThreadLocal深入理解二

    转载:http://doc00.com/doc/101101jf6 今天在看之前转载的博客:ThreadLocal的内部实现原理.突然有个疑问, 按照threadLocal的原理, 当把一个对象存入到 ...

  2. ThreadLocal 简单解析

    ThreadLocal 简单解析 基于jdk1.8 ThreadLocal一定不陌生,开发中常用,也是面试里的常客了,但是往往我们可能只是知道该类的作用.学习该类对于个人的多线程编码能力是大有裨益的, ...

  3. git的简单理解及基础操作命令

    前端小白一枚,最近开始使用git,于是花了2天看了廖雪峰的git教程(偏实践,对于学习git的基础操作很有帮助哦),也在看<git版本控制管理>这本书(偏理论,内容完善,很不错),针对所学 ...

  4. 简单理解Struts2中拦截器与过滤器的区别及执行顺序

    简单理解Struts2中拦截器与过滤器的区别及执行顺序 当接收到一个httprequest , a) 当外部的httpservletrequest到来时 b) 初始到了servlet容器 传递给一个标 ...

  5. [转]简单理解Socket

    简单理解Socket 转自 http://www.cnblogs.com/dolphinX/p/3460545.html  题外话 前几天和朋友聊天,朋友问我怎么最近不写博客了,一个是因为最近在忙着公 ...

  6. Js 职责链模式 简单理解

    js 职责链模式 的简单理解.大叔的代码太高深了,不好理解. function Handler(s) { this.successor = s || null; this.handle = funct ...

  7. Deep learning:四十六(DropConnect简单理解)

    和maxout(maxout简单理解)一样,DropConnect也是在ICML2013上发表的,同样也是为了提高Deep Network的泛化能力的,两者都号称是对Dropout(Dropout简单 ...

  8. Deep learning:四十二(Denoise Autoencoder简单理解)

    前言: 当采用无监督的方法分层预训练深度网络的权值时,为了学习到较鲁棒的特征,可以在网络的可视层(即数据的输入层)引入随机噪声,这种方法称为Denoise Autoencoder(简称dAE),由Be ...

  9. 简单理解dropout

    dropout是CNN(卷积神经网络)中的一个trick,能防止过拟合. 关于dropout的详细内容,还是看论文原文好了: Hinton, G. E., et al. (2012). "I ...

随机推荐

  1. CSS3 background-image背景图片相关介绍

    这里将会介绍如何通过background-image设置背景图片,以及背景图片的平铺.拉伸.偏移.设置大小等操作. 1. 背景图片样式分类 CSS中设置元素背景图片及其背景图片样式的属性主要以下几个: ...

  2. 【.net 深呼吸】细说CodeDom(3):命名空间

    在上一篇文章中,老周介绍了表达式和语句,尽管老周没有把所有的内容都讲一遍,但相信大伙至少已经掌握基本用法.在本文中,咱们继续探讨 CodeDom 方面的奥秘,这一次咱们聊聊命名空间. 在开始之前,老周 ...

  3. JQuery easyUI DataGrid 创建复杂列表头(译)

    » Create column groups in DataGrid The easyui DataGrid has ability to group columns, as the followin ...

  4. 自定义搭建PHP开发环境

    学习了一段时间php了,因为之前是刚接触php,所以用的是集成安装包(wamp).现在想进一步了解apache.mysql.php之间的关系以及提升自己所以进行自定义搭建PHP开发环境.废话不多说,请 ...

  5. AFNetworking 3.0 源码解读(十)之 UIActivityIndicatorView/UIRefreshControl/UIImageView + AFNetworking

    我们应该看到过很多类似这样的例子:某个控件拥有加载网络图片的能力.但这究竟是怎么做到的呢?看完这篇文章就明白了. 前言 这篇我们会介绍 AFNetworking 中的3个UIKit中的分类.UIAct ...

  6. 深入解析Sqlite的完美替代者,android数据库新王者——Realm

    写在前面: 又到一年一度七夕虐狗节,看着大家忍受着各种朋友圈和QQ空间还有现实生活中的轮番轰炸,我实在不忍心再在这里给大家补刀,所以我觉得今天不虐狗,继续给大家分享有用的. 如果你比较关心androi ...

  7. [LintCode]——目录

    Yet Another Source Code for LintCode Current Status : 232AC / 289ALL in Language C++, Up to date (20 ...

  8. JQuery中的siblings()是什么意思

    jQuery siblings() 方法返回被选元素的所有同胞元素,并且可以使用可选参数来过滤对同胞元素的搜索. 实例演示:点击某个li标签后将其设置为红色,而其所有同胞元素去除红色样式. 1.创建H ...

  9. H3 BPM引擎API接口

    引擎API接口通过 Engine 对象进行访问,这个是唯一入口. 示例1:获取组织机构对象 this.Engine.Organization.GetUnit("组织ID"); 示例 ...

  10. 用Kotlin实现Android定制视图(KAD 06)

    作者:Antonio Leiva 时间:Dec 27, 2016 原文链接:https://antonioleiva.com/custom-views-android-kotlin/ 在我们阅读有关c ...