理清ThreadLocal、ThreadLocalMap、Thread之间的关系

简介: 理清ThreadLocal、ThreadLocalMap、Thread之间的关系

初看ThreadLocal代码时候,感觉到很绕。区区三个类,但他们之间的类关系和设计思路与我们平常写的业务代码是不太一样的。

让我们一起来看看这三个类之间错综复杂的关系吧。

三者关系概览

 

 

从上图我们可以发现Thread 中持有一个ThreadLocalMap ,这里你可以简单理解为就是持有一个数组,这个数组是Entry 类型的。 Entry 的key 是ThreadLocal 类型的,value 是Object 类型。也就是一个ThreadLocalMap 可以持有多个ThreadLocal。

三者之间的类关系

为什么ThreadLocalMap被设计为ThreadLocal的内部类

为什么要将ThreadLocalMpa设计为ThreadLocal的内部类,而不独立出来呢?其实这里涉及到内部类起到封装的作用,我们一起看一下源码

    /**
     * ThreadLocalMap is a customized hash map suitable only for
     * maintaining thread local values. No operations are exported
     * outside of the ThreadLocal class. The class is package private to
     * allow declaration of fields in class Thread.  To help deal with
     * very large and long-lived usages, the hash table entries use
     * WeakReferences for keys. However, since reference queues are not
     * used, stale entries are guaranteed to be removed only when
     * the table starts running out of space.
     */
    static class ThreadLocalMap {}

主要是说明ThreadLocalMap 是一个线程本地的值,它所有的方法都是private 的,也就意味着除了ThreadLocal 这个类,其他类是不能操作ThreadLocalMap 中的任何方法的,这样就可以对其他类是透明的。同时这个类的权限是包级别的,也就意味着只有同一个包下面的类才能引用ThreadLocalMap 这个类,这也是Thread 为什么可以引用ThreadLocalMap 的原因,因为他们在同一个包下面。

ThreadLocal中的ThreadLocalMap是什么时候和Thread绑定在一起

虽然Thread 可以引用ThreadLocalMap,但是不能调用任何ThreadLocalMap 中的方法。这也就是我们平时都是通过ThreadLocal 来获取值和设置值,看下以下代码

public class Test {
    public static void main(String[] args) {
        ThreadLocal<String> local = new ThreadLocal<>();
        local.set("hello world");
        System.out.println(local.get());
    }
}

在第一次调用ThreadLocal set() 方法的时候开始绑定的,来我们看下set 方法的源码

我们这里看似是调用ThreadLocal的set方法设置了hello world,实际上这个值已经被设置到当前线程Thread拥有的ThreadLocalMap中去了。

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
        //第一次的时候进来这里,因为ThreadLocalMap 还没和Thread 绑定
            createMap(t, value);
    }
    //这个时候开始创建一个新的ThreadLocalMap 赋值给Thread 进行绑定
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

我们调用ThreadLocal 的get 方法的时候,其实我们最后是通过调用ThreadLocalMap 来获取值的。看完了get和set方法后,我们会发现ThreadLocalMap其实是一个中间媒介,对于使用者而言我们与我们直接打交道的是ThreadLocal,只不过我们要想把值和线程绑定在一起是离不开ThreadLocalMap这个媒介的。

    public T get() {
        //这里通过获取当前的线程
        Thread t = Thread.currentThread();
        //通过线程来获取ThreadLocalMap ,还记得我们上面说的Thread 里面有一个ThreadLocalMap 属性吗?就是这里用上了
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }
    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

现在大家应该明白了,其实ThreadLdocalMap 对使用者来说是透明的,可以当作空气,我们一值使用的都是ThreadLocal,这样的设计在使用的时候就显得简单,然后封装性又特别好。

 

引用文章:

https://blog.csdn.net/weixin_45127309/article/details/102746772


目录
相关文章
|
7天前
|
安全 Java 开发者
Lock锁和AQS之间的关系与区别:基于第一原理的深入分析
【11月更文挑战第26天】在Java并发编程中,锁(Lock)和队列同步器(AbstractQueuedSynchronizer,简称AQS)是两个核心概念。它们为多线程环境下的同步和互斥提供了强大的支持。本文将从第一原理出发,深入探讨Lock锁和AQS之间的关系与区别,同时分析它们的相关概念、业务场景、历史背景、功能点以及底层原理,并使用Java代码进行模拟实现。
15 1
|
7月前
|
存储 安全 Java
|
7月前
|
Java 关系型数据库 MySQL
【数据库连接,线程,ThreadLocal三者之间的关系】
【数据库连接,线程,ThreadLocal三者之间的关系】
98 0
|
7月前
|
存储 安全 Java
synchronized 与多线程的哪些关系
synchronized 与多线程的哪些关系
46 0
|
算法 安全 Java
探索多线程编程:线程的本质、状态和属性
探索多线程编程:线程的本质、状态和属性
【10张图】管程内部,进去看看
【10张图】管程内部,进去看看
160 0
【10张图】管程内部,进去看看
Java实现多线程开发的四种方式,详解它们之间异同
Java实现多线程开发的四种方式,详解它们之间异同
Java实现多线程开发的四种方式,详解它们之间异同
|
缓存 Java
理论:第八章:线程是什么,有几种实现方式,它们之间的区别是什么,线程池实现原理,JUC并发包,ThreadLocal与Lock和Synchronize区别
理论:第八章:线程是什么,有几种实现方式,它们之间的区别是什么,线程池实现原理,JUC并发包,ThreadLocal与Lock和Synchronize区别
129 0
|
安全 Java 调度
Java多线程、使用多线程的优点、线程的创建和使用、Thread类、创建线程的两种方式继承Thread类、实现Runnable接口、Thread类的有关方法、线程的调度、无效的源发行版、线程的分类
Java多线程、使用多线程的优点、线程的创建和使用、Thread类、创建线程的两种方式继承Thread类、实现Runnable接口、Thread类的有关方法、线程的调度、无效的源发行版、线程的分类
Java多线程、使用多线程的优点、线程的创建和使用、Thread类、创建线程的两种方式继承Thread类、实现Runnable接口、Thread类的有关方法、线程的调度、无效的源发行版、线程的分类
|
存储 Java
ThreadLocal Thread ThreadLocalMap 之间的关系
ThreadLocal :每个线程通过此对象都会返回各自的值,互不干扰,这是因为每个线程都存着自己的一份副本。需要注意的是线程结束后,它所保存的所有副本都将进行垃圾回收(除非存在对这些副本的其他引用) ThreadLocal的get操作是这样执行的:ThreadLocalMap map = thread.threadLocals -> return map.getEntry(threadLocal)ThreadLocal的set操作是这样执行的:ThreadLocalMap map = thread.threadLocals -> map.set(threadLocal, value)
ThreadLocal Thread ThreadLocalMap 之间的关系