热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

ThreadLocal原理浅析

ThreadLocal即线程局部变量的意思!所以什么是线程局部变量?这玩意有什么鸟用?是不是面试被问到了说不出个一二三?今天就来扒一扒这货的源码,从根本上了解这货是干啥的。
ThreadLocal即线程局部变量的意思!所以什么是线程局部变量?这玩意有什么鸟用?是不是面试被问到了说不出个一二三?今天就来扒一扒这货的源码,从根本上了解这货是干啥的。

Thread、ThreadLocalMap、Entry三者关系

其实研究下来他的源码实现,其实也没想象的那么复杂,其最主要有以下几点:

1、Java可以通过Thread.currentThread()来获得当前的Thread的实例对象。既然能拿到这Thread对象实例,那么我们就可以操作该实例(的属性),比如为该Thread对象设置一个值什么。

2、每一个Thread对象都有一个ThradLocalMap实例,该实例有一个一个Entry组成的数组,Entry对象有两个主要属性:value和ThreadLocal的弱引用,其中value这个属性就是值设置给当前线程所持有,也是ThreadLocal的核心属性:

static class Entry extends WeakReference> {
    /** The value associated with this ThreadLocal. */
    Object value;

    Entry(ThreadLocal k, Object v) {
        super(k);
        value = v;
    }
}

注意Entry继承自WeakReference,其key就是ThreadLocal对象!(图1)

通过上图我们可以得出这么一个结论:一个Thread对象持有一个ThreadLocalMap对象,然后呢,一个ThreadLoalMap对象又包含了多个ThreadLlocal对象及ThreadLocal对象所在线程的value!!!一言以蔽之: 一个Thread对象可以持有多个ThreadLocal对象的变量值value

那么ThreadLocal和Thread又有啥关系呢?二者是怎能对value进行读取的呢?下面就根据源码来简单的分析下。

ThreadLocal和Thread的关联

先看看ThreadLocal的set方法:

 public void set(T value) {
         //获取当前线程
        Thread t = Thread.currentThread();
        //获取当前线程持有的ThreadLocalMap
        ThreadLocal.ThreadLocalMap map = getMap(t);
        //将value设置给threadlocalMap
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

set方法很逻辑很简单(j结合上图2看更好理解):

1、通过currentThread方法拿到当前Thread对象

2、获取当前Thread对象的ThreadLoalMap对象

3、将value连同ThreadLocal对象自己组成一个Entry对象保存在

ThreadLoalMap的Entry类型的数组中。

在来看看ThreadLocal的get方法:

public T get() {
    //获取当前线程
    Thread t = Thread.currentThread();
    //获取当前线程的ThreadLocalMap对象
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        //获取与ThreadLocal对象想关联的value
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            //获取值
            T result = (T)e.value;
            return result;
        }
    }
    //为空返回初始化值
    return setInitialValue();
}

可以发展get的整体逻辑也很简单:

1、获取当前Thread对象

2、获取当前Thread对象的ThreadLocalMap对象

3、从ThreadLocalMap中获取与ThreadLocal相关联的Entry对象,具体的就是以ThreadLocal为key获取。

4、获取步骤3的Entry的value属性,并返回之。

通过整体观察get和set方法可以得出如下结论:ThreadLocal对象调用set方法就是往Thread对象的ThreadLocalMap里面添加值;ThreadLocal对象调用get方法就是从Thread对象的ThreadLocalMap里面获取值。核心就是操纵Thread对象的ThreadLocalMap对象进行value的读和写。原理就这么简单。

那么位于不同线程的不同ThreadLocal对象,在其他线程里保存值是一个什么样的关系呢?可以通过下图来清晰的描述出来:

ThreadLocal的使用实例

我们在知道在Android中一个线程只有一个Looper对象,那么是怎么做到的呢?就是ThreadLocal发挥了作用,看看Looper的prepare方法:

//定义一个静态的ThreadLocal变量
static final ThreadLocal sThreadLocal = new ThreadLocal(); 

private static void prepare(boolean quitAllowed) {
        //一个Thread只能关联一个Looper对象
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

观察prepare方法可以知道,先通过sThreadLocal的get方法判断当前线程是否已经拥有了一个Looper对象,如果有就抛出一个异常;如果当前线程还没有设置Looper对象,则调用ThreadLocal的set方法,初始化一个Looper对象交给当前线程:

sThreadLocal.set(new Looper(quitAllowed));

这样就确保了一个线程只有一个Looper对象。

到此为止,关于ThreadLocal的原理已经基本分析完毕,至于内部是怎么set和get的,博主并没有做太细的分析,因为没必要,了解ThreadLocal的工作原因以及使用场景即可。

以上就是ThreadLocal原理浅析的详细内容,更多请关注其它相关文章!


推荐阅读
  • 本文深入探讨了Java多线程环境下的同步机制及其应用,重点介绍了`synchronized`关键字的使用方法和原理。`synchronized`关键字主要用于确保多个线程在访问共享资源时的互斥性和原子性。通过具体示例,如在一个类中使用`synchronized`修饰方法,展示了如何实现线程安全的代码块。此外,文章还讨论了`ReentrantLock`等其他同步工具的优缺点,并提供了实际应用场景中的最佳实践。 ... [详细]
  • 这是一道涉及数学计算的问题。假设步行速度为 \(a\),车速为 \(b\),总距离为 \(c\)。Teddy 的步行时间为 \(T_1\),WhereIsHeroFrom 的步行时间为 \(T_2\),总时间为 \(T\)。通过分析不同时间段内的速度变化,可以得出最优的车辆使用策略,以最小化总的旅行时间。具体来说,需要计算在不同情况下步行和乘车的时间分配,以确保整体效率最大化。 ... [详细]
  • Java能否直接通过HTTP将字节流绕过HEAP写入SD卡? ... [详细]
  • 题目探讨了在无向图中求解点连通数的问题,具体涉及UVA1660和POJ1966两个经典问题。通过最小割算法的应用,分析了如何高效地确定网络中的关键节点和路径,为电缆电视网络的优化设计提供了理论支持。该研究不仅验证了最小割算法的有效性,还为进一步探索复杂网络的连通性和鲁棒性奠定了基础。 ... [详细]
  • 在 POJ1651 的乘法谜题挑战中,如果选手按相反顺序选择卡片,即先选 50,再选 20,最后选 1,则最终得分会有所不同。题目要求输入的第一行包含... 改写后的摘要:在 POJ1651 的乘法谜题挑战中,如果选手按照逆序选取卡片,例如依次选择 50、20 和 1,最终的得分将发生变化。题目首先要求输入的第一行包括... ... [详细]
  • 深入解析 Android 中 EditText 的 getLayoutParams 方法及其代码应用实例 ... [详细]
  • 资源管理器的基础架构包括三个核心组件:1)资源池,用于将CPU和内存等资源分配给不同的容器;2)负载组,负责承载任务并将其分配到相应的资源池;3)分类函数,用于将不同的会话映射到合适的负载组。该系统提供了两种主要的资源管理策略。 ... [详细]
  • CSS3 @font-face 字体应用技术解析与实践
    在Web前端开发中,HTML教程和CSS3的结合使得网页设计更加多样化。长期以来,Web设计师受限于“web-safe”字体的选择。然而,CSS3中的`@font-face`规则允许从服务器端加载自定义字体,极大地丰富了网页的视觉效果。通过这一技术,设计师可以自由选择和使用各种字体,提升用户体验和页面美观度。本文将深入解析`@font-face`的实现原理,并提供实际应用案例,帮助开发者更好地掌握这一强大工具。 ... [详细]
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • AngularJS 进阶指南:第三部分深入解析
    在本文中,我们将深入探讨 AngularJS 的指令模型,特别是 `ng-model` 指令。`ng-model` 指令用于将 HTML 元素与应用程序数据进行双向绑定,支持多种数据类型验证,如数字、电子邮件地址和必填项检查。此外,我们还将介绍如何利用该指令优化表单验证和数据处理流程,提升开发效率和用户体验。 ... [详细]
  • 本文深入解析了Java面向对象编程的核心概念及其应用,重点探讨了面向对象的三大特性:封装、继承和多态。封装确保了数据的安全性和代码的可维护性;继承支持代码的重用和扩展;多态则增强了程序的灵活性和可扩展性。通过具体示例,文章详细阐述了这些特性在实际开发中的应用和优势。 ... [详细]
  • 提升Android开发效率:Clean Code的最佳实践与应用
    在Android开发中,提高代码质量和开发效率是至关重要的。本文介绍了如何通过Clean Code的最佳实践来优化Android应用的开发流程。以SQLite数据库操作为例,详细探讨了如何编写高效、可维护的SQL查询语句,并将其结果封装为Java对象。通过遵循这些最佳实践,开发者可以显著提升代码的可读性和可维护性,从而加快开发速度并减少错误。 ... [详细]
  • 在探讨Hibernate框架的高级特性时,缓存机制和懒加载策略是提升数据操作效率的关键要素。缓存策略能够显著减少数据库访问次数,从而提高应用性能,特别是在处理频繁访问的数据时。Hibernate提供了多层次的缓存支持,包括一级缓存和二级缓存,以满足不同场景下的需求。懒加载策略则通过按需加载关联对象,进一步优化了资源利用和响应时间。本文将深入分析这些机制的实现原理及其最佳实践。 ... [详细]
  • 单链表的高效遍历及性能优化策略
    本文探讨了单链表的高效遍历方法及其性能优化策略。在单链表的数据结构中,插入操作的时间复杂度为O(n),而遍历操作的时间复杂度为O(n^2)。通过在 `LinkList.h` 和 `main.cpp` 文件中对单链表进行封装,我们实现了创建和销毁功能的优化,提高了单链表的使用效率。此外,文章还介绍了几种常见的优化技术,如缓存节点指针和批量处理,以进一步提升遍历性能。 ... [详细]
  • 小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限
    小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限 ... [详细]
author-avatar
蜡笔小新11953150
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有