• ThreadLocal简单理解


    在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
  • 相关阅读:
    [转]三五个人十来条枪 如何走出软件作坊成为开发正规军
    [转]asp.net页面字体变大问题总结
    [练手7]传值和传引用区别
    [练手3]选择排序
    [练手5]希尔排序
    oracle用select for update 中断后无法操作表的处理:杀掉SESSION
    [转]最省时管理法:让你一天随意
    [练手4]插入排序
    没有对“C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files”的写访问权限
    NUnit单元测试编写指南
  • 原文地址:https://www.cnblogs.com/5207/p/5795624.html
Copyright © 2020-2023  润新知