• 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
  • 相关阅读:
    配置JAVA的环境变量
    Navicat Premium v12.0.23.0 安装,使用激活码激活
    mysql 5.7.33安装教程
    查看mysql服务
    postman测试post请求参数是List entity后端用@RequestBody接受lIst entity方式
    最简单的MySQL安装教程(数据库免安装版,免安装版,亲测好用) mysql-5.7.33-winx64.zip
    mysql数据库安装5.7.33
    java删除附件图片
    java生成条形码
    最高的牛
  • 原文地址:https://www.cnblogs.com/5207/p/5795624.html
Copyright © 2020-2023  润新知