ThreadLocal原理讲解

简介: ThreadLocal原理讲解

ThreadLocal原理讲解

ThreadLocal 是 Java 中的一个类,它提供了线程局部变量的功能。如果你创建一个 ThreadLocal 变量,每个访问该变量的线程都会得到该变量的一个独立副本,这样每个线程都可以独立地改变自己的副本,而不会影响其他线程中的副本。

线程局部变量的功能

好的,让我们用一个小故事来形象地解释一下ThreadLocal,也就是线程局部变量的功能。

想象我们现在在一个大型的办公室里,这个办公室里有很多工作站,每个工作站都有自己的抽屉。这些工作站就好比是计算机中的线程,而抽屉就好像是ThreadLocal提供的线程局部变量。

现在,假设每个员工(线程)每天上班来到办公室(程序)后,都需要一个安全的地方来存放他们的个人物品,比如钥匙、手机或者是午餐。如果我们没有ThreadLocal这样的机制,那么所有员工可能就需要使用一个公共的储物柜。这样一来,每当任何一个员工想要取用自己的物品时,他们都必须排队等待,因为同一时间只有一个人能够使用这个储物柜。这会造成很大的混乱和效率低下,因为员工们需要消耗大量的时间等待,而不是做自己的工作。

现在,引入了ThreadLocal,也就是给每个工作站(线程)都配备了一个私人抽屉(线程局部变量)。员工们现在可以轻松地存取自己的个人物品,而不会受到其他人的干扰。每个员工都有自己独立的空间,他们不需要等待,也不用担心自己的物品会被别人误用。这样,每个人都可以更加专注于自己的工作,提高整个办公室的效率。

在编程的世界里,ThreadLocal的作用就是这样的。它为每个线程提供了一个独立的变量副本,每个线程可以独立地修改自己的副本而不会影响到其他线程。这在处理一些线程安全的操作时非常有用,比如日期格式化或者数据库连接等,这些操作往往不是线程安全的,或者它们的状态不应该被多个线程共享。

ThreadLocal 的原理:

  1. 存储结构:ThreadLocal 类内部使用一个 Map 来存储每个线程的局部变量。在 Java 中,这个 Map 被封装在 Thread 类的 ThreadLocal.ThreadLocalMap 属性中。
  2. 键的唯一性:Map 中的键是对 ThreadLocal 对象的引用,这确保了每个线程可以关联到它自己的、独立的变量副本。
  3. 值的隔离:当线程首次通过 ThreadLocal 访问变量时,ThreadLocal 会为这个线程在 Map 中创建一个副本。以后,该线程对 ThreadLocal 变量的所有访问都将直接映射到这个副本。
  4. 线程封闭:由于每个线程都有自己的变量副本,这就实现了线程封闭,避免了并发问题和线程间的数据共享。

设计一个ThreadLocal时,我们的目标是避免使用显式的锁机制,因为ThreadLocal的主要优势之一就是消除了线程间的竞争。在Java中,ThreadLocal通常是通过使用内部的ThreadLocalMap来实现的,这是一个与线程相关联的映射,其中键是ThreadLocal对象本身,而值是线程特定的数据。

在Java中,ThreadLocal的实现通常不需要显式的锁,因为每个线程都有自己的ThreadLocalMap,这样就避免了多线程竞争。但为了说明如何设计,下面是一个简化的ThreadLocal实现的伪代码,包括对映射的访问如何被同步:

public class ThreadLocal<T> {
    private Map<Thread, T> threadMap = Collections.synchronizedMap(new HashMap<>());
    public T get() {
        Thread currentThread = Thread.currentThread();
        return threadMap.get(currentThread);
    }
    public void set(T value) {
        Thread currentThread = Thread.currentThread();
        threadMap.put(currentThread, value);
    }
    public void remove() {
        Thread currentThread = Thread.currentThread();
        threadMap.remove(currentThread);
    }
}

在这个简化的版本中,我们使用了Collections.synchronizedMap来包装HashMap,从而提供一个线程安全的映射。这意味着每个对映射的访问(get、set、remove方法)都是同步的,因此不需要显式的锁对象。然而,这种做法并不是Java中ThreadLocal的典型实现方式,因为它引入了不必要的同步开销。

在实际的Java实现中,每个线程都有自己的ThreadLocalMap,这个映射是在线程对象内部维护的。这样,每个线程只能访问自己的ThreadLocalMap,因此不需要额外的同步。下面是一个更接近Java实际实现的伪代码:

public class ThreadLocal<T> {
    public T get() {
        Thread currentThread = Thread.currentThread();
        ThreadLocalMap map = currentThread.getThreadLocalMap();
        return (T) map.get(this);
    }
    public void set(T value) {
        Thread currentThread = Thread.currentThread();
        ThreadLocalMap map = currentThread.getThreadLocalMap();
        map.set(this, value);
    }
    public void remove() {
        Thread currentThread = Thread.currentThread();
        ThreadLocalMap map = currentThread.getThreadLocalMap();
        map.remove(this);
    }
    static class ThreadLocalMap {
        private Map<ThreadLocal<?>, Object> map = new HashMap<>();
        public Object get(ThreadLocal<?> key) {
            return map.get(key);
        }
        public void set(ThreadLocal<?> key, Object value) {
            map.put(key, value);
        }
        public void remove(ThreadLocal<?> key) {
            map.remove(key);
        }
    }
}
相关文章
|
6月前
|
存储 安全 Java
面试题:用过ThreadLocal吗?ThreadLocal是在哪个包下的?看过ThreadLocal源码吗?讲一下ThreadLocal的get和put是怎么实现的?
字节面试题:用过ThreadLocal吗?ThreadLocal是在哪个包下的?看过ThreadLocal源码吗?讲一下ThreadLocal的get和put是怎么实现的?
78 0
|
3月前
|
存储 设计模式 安全
深入理解ThreadLocal原理
本文深入探讨了Java中的ThreadLocal及其内部数据结构ThreadLocalMap的工作原理和特性,帮助读者理解如何利用ThreadLocal实现线程局部变量的隔离和线程安全。
深入理解ThreadLocal原理
|
4月前
|
存储 算法 Java
ThreadLocal 源码浅析
【7月更文挑战第5天】`ThreadLocal` 是Java中用于创建线程局部变量的工具类,确保每个线程拥有独立的变量副本。源码中,每个`ThreadLocal`实例都有一个唯一的哈希码用于映射到`ThreadLocalMap`,这个内部静态类使用弱引用存储键(`ThreadLocal`实例)以防止内存泄漏。`ThreadLocalMap`使用 Entry 数组,Entry 是一个扩展了 WeakReference 的类,持有线程变量值。`ThreadLocal`的`get()`和`set()`方法通过哈希计算定位并访问或设置线程局部变量。
|
存储 Java
大厂是怎么用ThreadLocal?ThreadLocal核心原理分析
ThreadLocal**是Java中的一个线程本地变量类。它可以让每个线程都有自己独立的变量副本,而不会相互影响。
119 1
|
Java 数据库连接
ThreadLocal原理和实践
ThreadLocal是线程本地变量,解决多线程环境下成员变量共享存在的问题。ThreadLocal为每个线程创建独立的的变量副本,他的特性是该变量的引用对全局可见,但是其值只对当前线程可用,每个线程都将自己的值保存到这个变量中而各线程不受影响。
162 0
ThreadLocal原理和实践
|
存储 SpringCloudAlibaba Java
浅析ThreadLocal使用及实现原理
提供了线程局部 (thread-local) 变量。这些变量不同于它们的普通对应物,因为访问某个变量(通过其`get` 或 `set`方法)的每个线程都有自己的局部变量,它独立于变量的初始化副本。`ThreadLocal`实例通常是类中的 private static 字段,它们希望将状态与某一个线程(例如,用户 ID 或事务 ID)相关联 。所以ThreadLocal与线程同步机制不同,线程同步机制是多个线程共享同一个变量,而ThreadLocal是为每一个线程创建一个单独的变量副本,故而每个线程都可以独立地改变自己所拥有的变量副本,而不会影响其他线程所对应的副本。可以这么说Th
109 0
浅析ThreadLocal使用及实现原理
|
存储 算法 安全
ThreadLocal原理剖析
ThreadLocal原理剖析
222 0
|
存储 安全 Java
ThreadLocal源码分析
ThreadLocal,即线程局部变量。主要用于线程间数据隔离。这些变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量,ThreadLocal实例通常来说都是private static类型。ThreadLocal不是为了解决多线程访问共享变量,而是为每个线程创建一个单独的变量副本,提供了保持对象的方法和避免参数传递的复杂性。
|
Java 定位技术
ThreadLocal原理
经典八股文之ThreadLocal原理
190 0