ThreadLocal最全详解(实现原理及用法使用)

文摘   2024-08-26 12:59   四川  

关注mikechen的架构笔记十余年BAT架构经验倾囊相授


大家好,我是mikechen。

ThreadLocal是解决多线程环境中,共享资源问题的并发工具,也是大厂喜欢考察的内容,下面我就全面来详解ThreadLocal@mikechen

ThreadLocal

ThreadLocal是 “Java并发编程”,用于为每个线程提供独立的变量副本,使得每个线程都可以修改自己的副本,而不会影响其他线程的副本。

比如,多个线程可以有多个副本,如下图所示:

在多线程环境中,有时需要每个线程持有自己独立的对象副本,以避免线程间的共享资源冲突。

比如:数据库连接,为每个线程创建独立的数据库连接实例,从而避免多个线程同时操作同一个连接导致的线程不安全问题。

总之,处理一些非线程安全的对象时,可以通过 ThreadLocal 为每个线程提供一个独立的实例副本。


ThreadLocal原理

ThreadLocal 的实现:依赖于每个线程持有一个 ThreadLocalMap,这个映射表的键是 ThreadLocal 对象,值是线程对该 ThreadLocal 对象所存储的变量副本。

ThreadLocal结构,如下图所示:

Thread

Thread 是 Java 中的基本线程类,每个线程在执行时都由 Thread 对象来表示,Thread 对象管理着线程的生命周期和线程的各种属性。

在 Thread 类中,有一个属性用来存储该线程的局部变量,即 :ThreadLocalMap。

ThreadLocal

ThreadLocal 是一个用于创建线程局部变量的类每,个线程都拥有一个独立的副本,ThreadLocal 提供了一种机制来维护和获取这些副本。

ThreadLocal 通过 :set()、get()、remove() 方法来操作线程局部变量。

比如:

  • T get(): 返回当前线程对应的线程局部变量副本的,如果该线程之前没有通过 set() 设置过值,则会调用 initialValue() 方法;

  • void set(T value): 为当前线程设置线程局部变量副本的值;

  • void remove(): 移除当前线程的线程局部变量副本的值,避免内存泄漏;

  • T initialValue(): 返回线程局部变量的初始值,默认实现返回 null,可以通过子类化 ThreadLocal 来覆盖这个方法。

public class ThreadLocalExample {    private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 1);
public static void main(String[] args) { Thread t1 = new Thread(() -> { System.out.println("Thread 1 initial value: " + threadLocal.get()); threadLocal.set(100); System.out.println("Thread 1 after set value: " + threadLocal.get()); });
Thread t2 = new Thread(() -> { System.out.println("Thread 2 initial value: " + threadLocal.get()); threadLocal.set(200); System.out.println("Thread 2 after set value: " + threadLocal.get()); });
t1.start(); t2.start(); }}

ThreadLocalMap 类

ThreadLocalMap 是 Thread 类中的一个内部类,用于存储线程局部变量。

ThreadLocalMap 实质上是一个自定义的哈希表,键是 ThreadLocal 对象,值是 ThreadLocal 对应的线程局部变量值。

ThreadLocalMap 的作用:就是为每个 ThreadLocal 对象维护一个单独的变量副本。

ThreadLocalMap 只存在于 Thread 对象中,因此每个线程有自己独立的 ThreadLocalMap,不会与其他线程共享。

这三者共同作用,实现了线程局部变量的隔离,从而避免了线程之间的数据竞争问题。

ThreadLocal使用

有时候,我们希望在线程的不同方法中共享某些上下文信息,这样可以避免频繁的传递参数。

在这个例子中,UserContext 类使用 ThreadLocal 来存储每个线程的当前用户信息。

如下所示:

public class UserContext {    private static ThreadLocal<String> userThreadLocal = new ThreadLocal<>();
public static void setCurrentUser(String user) { userThreadLocal.set(user); }
public static String getCurrentUser() { return userThreadLocal.get(); }
public static void clear() { userThreadLocal.remove(); }}
// 使用示例public class UserService { public void processUserRequest() { String currentUser = UserContext.getCurrentUser(); // 处理与 currentUser 相关的业务逻辑 }}

在处理请求的过程中,不同的方法可以直接从 ThreadLocal 获取当前用户信息,而不需要在方法之间传递用户信息。


以上


最后送大家一个福利:

送我原创超30万字阿里架构师进阶专题合集


以及给大家整理最全大厂Java面试题及答案详解,包含:Java、多线程、JVM、Spring、MySQL、Redis、中间件...等必考题答案详解。


需要以上架构专题&面试答案的同学,加我微信即可领取!


添加时备注:资料





mikechen的架构笔记
十余年BAT架构经验倾囊相授!
 最新文章