前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ThreadLocal简单理解

ThreadLocal简单理解

作者头像
用户1105954
发布2018-01-12 18:01:53
5090
发布2018-01-12 18:01:53
举报
文章被收录于专栏:mini188mini188

在java开源项目的代码中看到一个类里ThreadLocal的属性:

代码语言:javascript
复制
private static ThreadLocal<Boolean> clientMode = new ThreadLocal<>();

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

原来它的意思是线程的本地变量,ThreadLocal更像是一个线程变量访问的工具类。

那为什么要用这种方法呢?

翻看了《Java并发编程实践》,看到这么一个说法:线程本地变量通常用于防止可变单例或者全局变量的设计中,出现不正确的共享。

感觉这个看着很生硬啊。书中也举了例子,是JDBC的Connection的应用。Connection对于单线程的程序中,一般会启动时就创建好,这样就不用每次都创建对象啦。但是换到多线程环境下就不行了,因为JDBC规范并没有要求Connection是线程安全的。那么如果要解决就可以使用ThreadLocal。使用ThreadLocal可以在每个线程中创建一个Connection对象,这样就满足线程安全要求了。

这里比较好奇的是ThreadLocal是如何做到这些的呢?

ThreadLocal的实现

打开源代码,ThreadLocal是个泛型类,里面也并不复杂,看到的构造函数也是什么也没有做。ThreadLocal中比较常用的方法主要是set和get。最主要的奥秘便是下面这几行代码:

代码语言:javascript
复制
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将变量设置到线程中的方法:

代码语言:javascript
复制
/**
     * 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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016-08-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档