ThreadLocal

ThreadLocal 是Java中 lang 包下的一个类,是用来解决多线程下共享变量并发问题的,所谓共享变量即同一个变量在不同线程下赋予不同值, 而ThreadLocal会在不同线程中维护共享变量的独立副本

前置 线程池

是 Java 中提供的一种用于实现线程局部变量的工具类。它允许每个线程都拥有自己的独立副本,从而实现线程隔离,用于解决多线程中共享对象的线程安全问题。

image.png

使用:

创建 ThreadLocal对象

//创建一个ThreadLocal变量
public static ThreadLocal<String> localVariable = new ThreadLocal<>();

设置值

//设置ThreadLocal变量的值 localVariable.set("0001");

获取值

//获取ThreadLocal变量的值 String value = localVariable.get();

优点

  1. 线程隔离 实现了变量的独占, 使变量不需要同步处理

  2. 数据传递方便 ThreadLocal 常用于在跨方法、跨类时传递上下文数据(如用户信息等),而不需要在方法间传递参数。

ThreadLocalMap

ThreadLocalMap, 一个key-value数据形式结构,也是ThreadLocal的核心。

Map内部维护了一个Entry数组, 真正的数据存储在 Entry中, map的key是每个线程中ThreadLocal对象的哈希, value是隔离变量

/**
	 * 初始容量
	 */
	private static final int INITIAL_CAPACITY = 16;
	
	/**
	 * ThreadLocalMap数据真正存储在table中
	 */
	private Entry[] table;
	
	/**
	 * ThreadLocalMap条数
	 */
	private int size = 0;
	
	/**
	 * 达到这个大小,则扩容
	 */
	private int threshold; // 默认为0

image.png

为了保证Entry[] 数组散步均匀, 哈希算法如下

把对应的 key 映射到 table 数组的相应下标,ThreadLocalMap 用的是哈希取余法,取出 key 的 threadLocalHashCode,然后和 table 数组长度减一&运算(相当于取余)。

int i = key.threadLocalHashCode & (table.length - 1);

这里的hashcode由魔术数生成 每创建一个 ThreadLocal 对象,它就会新增0x61c88647,这个值很特殊,它是斐波那契数 也叫 黄金分割数hash增量为 这个数字,带来的好处就是 hash 分布非常均匀

InheritableThreadLocal()

父子线程是无法传输数据的, 但是通过InheritableThreadLocal实例就可以在子线程拿到值

public class InheritableThreadLocalTest {

    public static void main(String[] args) {
        final ThreadLocal threadLocal = new InheritableThreadLocal();
        // 主线程
        threadLocal.set("父线程");
        //子线程
        Thread t = new Thread() {
            @Override
            public void run() {
                super.run();
                System.out.println("子线程 ," + threadLocal.get());
            }
        };
        t.start();
    }
}

原理:

在Thread中有一个变量

ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;

if (inheritThreadLocals && parent.inheritableThreadLocals != null)
    this.inheritableThreadLocals =
        ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);

在 Thread.init 的时候,如果父线程的inheritableThreadLocals不为空,就把它赋给当前线程(子线程)的inheritableThreadLocals 。

Last modified March 3, 2025: 组件笔记 3/3 (41127dd)