Java ThreadLocal 案例 + 原理深度解析
Java ThreadLocal 案例 原理深度解析ThreadLocal是 Java 提供的线程本地变量工具核心作用为每个线程创建独立的变量副本线程之间互不干扰实现线程安全。简单说同一个 ThreadLocal 变量在不同线程中值是独立的修改一个线程的值不会影响其他线程。一、完整可运行案例这个案例模拟多线程环境下每个线程独立存储自己的用户ID互不覆盖。public class ThreadLocalDemo { // 1. 创建 ThreadLocal 对象用于存储线程本地变量 private static final ThreadLocalInteger USER_ID new ThreadLocal(); public static void main(String[] args) { // 线程1设置用户ID为 100 new Thread(() - { USER_ID.set(100); System.out.println(线程1 Thread.currentThread().getName() 用户ID USER_ID.get()); // 用完必须移除防止内存泄漏 USER_ID.remove(); }, Thread-1).start(); // 线程2设置用户ID为 200 new Thread(() - { USER_ID.set(200); System.out.println(线程2 Thread.currentThread().getName() 用户ID USER_ID.get()); USER_ID.remove(); }, Thread-2).start(); // 主线程未设置值获取为 null System.out.println(主线程 Thread.currentThread().getName() 用户ID USER_ID.get()); } }运行结果线程顺序可能变化主线程main用户IDnull 线程1Thread-1用户ID100 线程2Thread-2用户ID200核心结论主线程、线程1、线程2 操作同一个 **USER_ID** 对象但值完全独立线程1设置100线程2设置200主线程无值线程之间没有任何干扰。二、ThreadLocal 核心用法3个方法方法作用set(T value)为当前线程设置变量值get()获取当前线程对应的变量值remove()删除当前线程的变量值必须使用用法注意事项必须手动调用 **remove()线程池场景下线程会复用不删除会导致内存泄漏**、数据错乱声明为static final全局唯一避免重复创建仅用于线程内部数据传递不能用于线程间通信。三、ThreadLocal 底层原理图解源码解析1. 核心数据结构每个Thread对象内部都有一个成员变量ThreadLocal.ThreadLocalMap threadLocals null;ThreadLocalMap是一个自定义哈希表key 是当前 ThreadLocal 对象value 是我们存储的值结构关系一个线程Thread→ 对应一个ThreadLocalMap一个ThreadLocalMap→ 可以存储多个ThreadLocal键值对变量隔离的本质数据存在线程自己的 Map 里和其他线程无关。2. 工作流程调用threadLocal.set(value)获取当前线程对象获取线程自己的ThreadLocalMap以ThreadLocal为 key存储 value调用threadLocal.get()获取当前线程的ThreadLocalMap以当前ThreadLocal为 key取出对应 value调用threadLocal.remove()删除当前线程 Map 中对应的键值对。3. 关键特性线程隔离数据绑定在当前线程其他线程无法访问弱引用ThreadLocalMap的 key 是弱引用GC 时会自动回收 key但 value 是强引用必须手动 remove 防止内存泄漏无锁设计不需要 synchronized性能比同步锁高很多。四、经典使用场景Web 项目存储用户登录信息拦截器中设置用户IDController/Service 中直接获取避免层层传递参数。2.数据库连接管理为每个线程分配独立的 Connection保证事务安全。五、避坑指南必看线程池必须 remove线程池中的线程会复用如果不 remove旧数据会残留到下一次使用导致业务错误不要存储大对象大对象会长期占用内存无法回收引发内存泄漏不能替代同步锁ThreadLocal 解决的是线程内部数据隔离synchronized 解决的是线程间共享数据安全场景不同。总结作用为每个线程创建独立变量副本实现线程安全、无锁隔离用法set()存值、get()取值、remove()删值核心原理数据存在线程自身的 ThreadLocalMap中线程之间互不共享关键用完必须remove()防止内存泄漏。