ThreadLocal源码浅析

简介:
  ThreadLocal不是一个具体的线程。它是一个线程内部的数据存储类,通过它可以再指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其它线程来说则无法获取到数据。
  ThreadLocal之所以有这么神奇的效果,是因为不同线程访问同一个ThreadLocal的get方法,ThreadLocal内部会将各自线程的引用当做table数组的一个值存在,然后从数组中根据当前ThreadLocal的reference去查找出相应的value。这就是为什么通过ThreadLocal可以再不同线程中维护一套数据的副本并且彼此互不干扰。
  在java中ThreadLocal以Map的形式存储数据(ThreadLocal对象为 key  数值为value)。在Android中做了些改动,在Thread-Local的add方法中,可以看到它会把ThradLocal对象(key)和相对应的value放在table数组连续的位置中。 也就是table被设计为下标为0,2,4...2n的位置存放key,而1,3,5...(2n +1 )的位置存放value。
void add(ThreadLocal<?> key, Object value) {
            for (int index = key .hash & mask ;; index = next(index )) {
                Object k = table[ index];
                if (k == null) {
                    table[ index] = key. reference;
                    table[ index + 1] = value;
                    return;
                }
            }
        }

类中最重要的两个方法是get(),set()。下面开始分析set()源码。
    public void set(T value ) {
        Thread currentThread = Thread.currentThread();
        Values values = values( currentThread);
        if (values == null) {
            values = initializeValues(currentThread );
        }
        values.put( this, value );
    }
首先获取当前线程对象 currentThread,然后执行values( currentThread )方法。源码如下:
Values values(Thread current) {
      return current .localValues;
  }
     在values (currentThread )中返回了currentThread .localValues。跟进Thread的源码可以发现:这个currentThread .localValues其实就是ThreadLocal.Values  localValues 。Values 是ThreadLocal中的一个静态内部类。此时获取到返回的Values对象。
     接下来进行判空操作,如果返回的values为空,那么再次实例化currentThread。跟进initializeValue-s(currentThread)可以发现
Values initializeValues(Thread current) {
        return current .localValues = new Values();
    }

new Values()的实例化过程:

       Values() {
            initializeTable( INITIAL_SIZE);//INITIAL_SIZE 默认值16
            this.size = 0;
            this.tombstones = 0;
        }

      private void initializeTable( int capacity ) {
            this.table = new Object[capacity * 2];
            this.mask = table .length - 1;
            this.clean = 0;
            this.maximumLoad = capacity * 2 / 3; // 2/3
        }
此时可以确保有了Values的一个实例,接下来就可以执行values .put(this, value ),跟进put方法
void put(ThreadLocal<?> key, Object value) {
            cleanUp();

            // Keep track of first tombstone. That's where we want to go back
            // and add an entry if necessary.
            int firstTombstone = -1;

            for (int index = key .hash & mask ;; index = next(index )) {
                Object k = table[ index];

                if (k == key .reference ) {
                    // Replace existing entry.
                    table[ index + 1] = value;
                    return;
                }

                if (k == null) {
                    if (firstTombstone == -1) {
                        // Fill in null slot.
                        table[ index] = key.reference ;
                        table[ index + 1] = value;
                        size++;
                        return;
                    }

                    // Go back and replace first tombstone.
                    table[ firstTombstone] = key.reference ;
                    table[ firstTombstone + 1] = value;
                    tombstones--;
                    size++;
                    return;
                }

                // Remember first tombstone.
                if (firstTombstone == -1 && k == TOMBSTONE) {
                    firstTombstone = index ;
                }
            }
        }

 依据上面的代码可以得出一个存储规则:ThreadLocal的值在table数组中的存储位置总是为reference字段所表示的对象的下一个位置。
table[index] =key.reference;
table[index+ 1] =value;
最终ThreadLocal的值会被存储在table数组中:table[index+ 1] =value;至此,set方法解析完毕。下面看一下get方法。

public T get() {
        // Optimized for the fast path.
        Thread currentThread = Thread.currentThread();
        Values values = values( currentThread);
        if (values != null) {
            Object[] table = values. table;
            int index = hash & values .mask ;
            if (this .reference == table [index ]) {
                return (T) table [index + 1];
            }
        } else {
            values = initializeValues(currentThread );
        }

        return (T) values .getAfterMiss(this);
    }
看完set方法后再看get就比较简单了,首先得到一个Values对象,然后求出table数组ThreadLocal.reference的下标。前文说过: ThradLocal对象(key)和相对应的value放在table数组连续的位置中。 也就是table被设计为下标为0,2,4...2n的位置存放key,而1,3,5...(2n +1 )的位置存放value。现在得到index后再index+1就是value在table数组中的下标。即value=table[index+1];return value即可。
到此想必读者对ThreadLocal为什么能在不同线程中能够为不同线程创建不同的线程副本(其实不太准确,应该是相同对象的不同值),原因就在于采用了key value形式的table数组。key为不同线程的reference,value就五花八门了。

        ThreadLocal浅析到此结束。谢谢欣赏~






相关文章
|
C# Windows
C#的安装教程
C#的安装教程
377 0
|
缓存 数据可视化 搜索推荐
Windows 上这些「点一下」就省 N 步的自动化软件,让你的效率快如火箭
Windows 上这些「点一下」就省 N 步的自动化软件,让你的效率快如火箭
1187 0
|
7月前
|
XML Java 开发者
通过springboot框架创建对象(一)
在Spring Boot中,对象创建依赖于Spring框架的核心特性——控制反转(IoC)和依赖注入(DI)。IoC将对象的创建和管理交由Spring应用上下文负责,开发者只需定义依赖关系。DI通过构造函数、setter方法或字段注入实现依赖对象的传递。Spring Boot的自动配置机制基于类路径和配置文件,自动为应用程序配置Spring容器,简化开发过程。Bean的生命周期包括定义扫描、实例化、依赖注入、初始化和销毁回调,均由Spring容器管理。这些特性提高了开发效率并简化了代码维护。
|
8月前
|
存储 弹性计算 固态存储
阿里云服务器ESSD Entry系统盘测评IOPS、IO读写和时延性能参数
阿里云ESSD Entry云盘是新一代企业级云盘,具备高IOPS、低延迟特性,适合开发与测试场景。它提供10~32,768 GiB容量范围,最大IOPS达6,000,吞吐量150 MB/s,时延1~3 ms。支持按量付费和包年包月,性价比高,特别适合个人开发者和中小企业。详情及价格参考阿里云官网。
|
10月前
|
机器学习/深度学习 算法 C++
数据结构之鲸鱼算法
鲸鱼算法(Whale Optimization Algorithm,WOA)是由伊朗研究员Seyedali Mirjalili于2016年提出的一种基于群体智能的全局优化算法,灵感源自鲸鱼捕食时的群体协作行为。该算法通过模拟鲸鱼的围捕猎物和喷出气泡网的行为,结合全局搜索和局部搜索策略,有效解决了复杂问题的优化需求。其应用广泛,涵盖函数优化、机器学习、图像处理等领域。鲸鱼算法以其简单直观的特点,成为初学者友好型的优化工具,但同时也存在参数敏感、可能陷入局部最优等问题。提供的C++代码示例展示了算法的基本实现和运行过程。
777 0
|
10月前
|
人工智能 安全 大数据
元宇宙游戏:沉浸式体验的新纪元
在科技飞速发展的今天,元宇宙游戏作为融合了虚拟现实(VR)、增强现实(AR)、人工智能(AI)与区块链等前沿技术的数字新世界,正引领我们进入一个前所未有的沉浸式体验时代。本文将深入探讨元宇宙游戏的特点、技术基础及其如何引领沉浸式体验的新潮流。
|
人工智能
将 JPEG 和 PNG 位图转换为 SVG 矢量图,可无限放大
将 JPEG 和 PNG 位图转换为 SVG 矢量图,可无限放大
554 1
|
存储 容灾 5G
阿里云快照收费吗?
阿里云服务器开通快照收费吗?阿里云服务器开通快照服务收费吗?开通快照不收费,使用快照收费,比如为云服务器的云盘创建快照,就会根据快照大小和存储时间收取快照费,一般中国大陆地域的云服务器快照价格为0.12元/GB/月。阿里云百科来详细说下阿里云服务器快照有什么用、收费价格以及快照的作用:
663 0
阿里云快照收费吗?
|
存储 弹性计算 监控
阿里企业邮箱_阿里云邮箱购买申请_钉钉企业邮箱
阿里企业邮箱_阿里云邮箱购买申请_钉钉企业邮箱
425 0
|
消息中间件 移动开发 运维
《2023云原生实战案例集》——04 互联网——小七手游 MQTT构筑运营平台与游戏端的交互通道
《2023云原生实战案例集》——04 互联网——小七手游 MQTT构筑运营平台与游戏端的交互通道