由浅入深全面剖析ThreadLocal

本文详细剖析了ThreadLocal的原理和用途,解释了它如何实现线程内部存储,以及在Android系统中的应用,如与Looper的关联。ThreadLocal提供get()、set()和remove()方法,用于在线程中存储和管理变量。通过源码解析,文章探讨了ThreadLocal的构造方法、存储机制,特别是其内部类Values的实现,包括如何利用斐波拉契散列生成有效索引。此外,文章还揭示了ThreadLocal在内存管理和寻址策略上的巧妙设计,引发对更高效寻址方法的思考。
摘要由CSDN通过智能技术生成

前言

这一阵子一直在看Picasso,在看的过程中发现了很多很有意思的东西,有的是以前见过甚至用过但是没有深入关注的,有些是以前根本没有见过的——比如今天要讲的ThreadLocal。(android 6.0)

正文

1,ThreadLocal是什么?

先看一下Android官网的文档:

Implements a thread-local storage, that is, a variable for which each thread has its own value. All threads share the same ThreadLocal object, but each sees a different value when accessing it, and changes made by one thread do not affect the other threads. The implementation supports null values.
实现了每个线程的自有变量的存储。所有线程共享同一个ThreadLocal对象,但是每个线程只能访问自己所存储的变量,并且线程之间做的改动互不影响。此实现支持null变量的存储。(非逐词翻译)

通过这个描述,我们可以知道一些信息:

  • ThreadLocal是一个线程的内部存储类,通过它我们可以在指定的线程中存储信息。
  • 每个线程之间的信息是独立且封闭的。

但是同时也会有一些疑问:

  • 所谓的自有变量是什么?
  • 通过什么形式存储?
  • 怎么对存储的信息进行操作?
  • 怎么实现的线程间的信息封闭且独立?
  • 等等

接下来我们就慢慢的在探索这个类的过程中,来从头到尾的弄清楚这些个疑问。

2,ThreadLocal的用途

ThreadLocal的作用是实现每个线程的自有变量的存储,这个“自有变量”具体是什么当然要根据不同的需求来定,但是在Android的源码中,这个自有变量常常是Looper。

这个Looper是什么呢?这里就不得不提到Android的消息机制了。Android的消息机制是指Handler的运行机制以及Handler所附带的MessageQueue和Looper的工作过程。简单来讲,就是Handler发送Message到MessageQueue中,而Looper不断的从MessageQueue中循环摘取Message,并进行进一步的解析处理。

但是Looper只是个简单的类而已,它虽然提供了循环处理方面的成员函数loop(),却不能自己凭空地运行起来,而只能寄身于某个真实的线程。那么Looper是怎么和线程建立联系的呢?这个时候ThreadLocal就参与其中了。

我们来看一下Looper的部分源码:

private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //调用ThreadLocal的set()方法将Looper存进去
        sThreadLocal.set(new Looper(quitAllowed));
}
 public static void loop() {
        //调用myLooper()方法得到Looper,我们接着看一下myLooper()方法
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        …… ……
}
public static @Nullable Looper myLooper() {
        //调用ThreadLocal的get()方法得到刚才存入的Looper对象
        return sThreadLocal.get();
}

关于ThreadLocal的set()和get()方法是怎么对Looper进行操作并将其存入Thread中的下文会有详述。在这里我们可以清楚的看到ThreadLocal的踪迹并对它的用途有一个比较清晰的认识:当某个变量是与线程相关的并且不同线程具有不同值的时候,我们就可以考虑使用ThreadLocal这个类来简化我们的工作(比如Looper)。

更多ThreadLocal的具体用途大家可以看下任教主的这篇博文:Android的消息机制之ThreadLocal的工作原理

3,ThreadLocal用法

它的用法其实挺简单的,暴露出来的方法一共只有三个:

  • get():返回调用线程中变量的当前值
  • set(T value):设置调用线程中变量的值
  • remove():移除调用线程的当前变量

用的话也是这三个方法,就跟上面Looper里面的用法差不多。例子的代码如下:

mIntegerThreadLocal = new ThreadLocal<>();

mIntegerThreadLocal.set(0);
//在主线程里设置mIntegerThreadLocal的值为0,输出0
Log.d(TAG, "[Thread#main]mIntegerThreadLocal=" + mIntegerThreadLocal.get());

new Thread("Thread#1") {
    @Override
    public void run() {
        //设置mIntegerThreadLocal的值为1,输出1
        mIntegerThreadLocal.set(1);
        Log.d(TAG, "[Thread#1]mIntegerThreadLocal=" + mIntegerThreadLocal.get());
    }
}.start();

new Thread("Thread#2") {
    @Override
    public void run() {
        //不设置任何值,输出null
        Log.d(TAG, "[Thread#2]mIntegerThreadLocal=" + mIntegerThreadLocal.get());
    }
}.start();

new Thread("Thread#3") {
    @Override
    public void run() {
        //设置为3,然后remove,输出null
        mIntegerThreadLocal.set(3);
        mIntegerThreadLocal.remove();
        Log.d(TAG, "[Thread#3]mIntegerThreadLocal=" + mIntegerThreadLocal.get());
    }
}.start();

输出结果如下:

05-08 16:08:24.771 14423-14423/com.lypeer.apifinder D/MainActivity: [Thread#main]mIntegerThreadLocal=0
05-08 16:08:24.774 14423-14447/com.lypeer.apifinder D/MainActivity: [Thread#2]mIntegerThreadLocal=null
05-08 16:08:24.780 14423-14446/com.lypeer.apifinder D/MainActivity: [Thread#1]mIntegerThreadLocal=1
05-08 16:08:24.781 14423-14448/com.lypeer.apifinder D/MainActivity: [Thread#3]mIntegerThreadLocal=null

事实证明,ThreadLocal确实做到了官方文档里说到的功能:存储Thread的信息,并且每个线程之间信息独立,即它们只能访问自己对应的信息,并且修改自己对应的信息之后对其他线程没有影响。

4,源码解析

4.1,构造方法

先看一下它的构造方法:

 public ThreadLocal() {}

可以的,啥都没干,空构造,这条路子走不通。

4.2,暴露方法

4.2.1,public void set(T value)

接下来从暴露出来的方法入手,先看set()方法:


                
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值