ThreadLocal 实现多线程存取数据场景模型

本文深入解析了ThreadLocal在Java多线程编程中的应用,探讨了其如何实现线程隔离的变量存储,以及其底层原理和常见问题解答。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求场景

需要多线程运行程序时候,虽然有很多变量可以是不同线程间通用,但是还是有些变量希望做到线程隔离,每个线程需要自己独有的一些变量的场景模型

ThreadLocal 介绍

早在 jdk 1.2 的版本中就提供了 java.lang.ThreadLocal 的支持,这个工具可以帮助我们很方便的写出多线程的一些程序
常用方法如下:

  • ThreadLocal.get 获取当前线程存储进 ThreadLocal 的变量
  • ThreadLocal.set 设置当前线程 ThreadLocal 中的变量
  • ThreadLocal.remove 移除当前线程 ThreadLocal 中的变量

ThreadLocal 一些问题

  1. 同一个线程,多次 new ThreadLocal,对不同的对象 set(不同参数) 操作之后,当前线程本地存储的值会被覆盖吗?
    答案是不会的,这些值会全部存进线程相关的某个 map 中,这些值也依然做到线程隔离,但是不会被覆盖,都存在了本地线程存储中
  2. 其底层原理是通过存储线程号加上值的 map 形式吗?
    答案是否定的,是通过存储 ThreadLocal 对象(key)加上值(value)的形式存储进一个线程相关的 map 中

这些问题都可以查看下方底层原理,从中可以得到解释

ThreadLocal 底层原理

当我们在一个类中设立一个 static ThreadLocal,在不同线程中存取 ThreadLocal 时候为什么是不同的值呢?
因为其底层代码如下:
这是 ThreadLocal.set 方法

public void set(T value) {
	Thread t = Thread.currentThread();
	ThreadLocalMap map = getMap(t);
	if (map != null)
		map.set(this, value);
	else
	createMap(t, value);
}

这是 ThreadLocal.get 方法

public T get() {
	Thread t = Thread.currentThread();
	ThreadLocalMap map = getMap(t);
	if (map != null) {
		ThreadLocalMap.Entry e = map.getEntry(this);
		if (e != null) {
			T result = (T)e.value;
			return result;
		}
	}
	return setInitialValue();
}

我们可以发现,当我们写 ThreadLocal 变量虽然是 static 静态,但是不同线程存储时候却能够做到线程之间不串扰,这是因为,当我们每次 set 存数据时候,虽然threadLocal.set("aaa")只用填 value,但实际底层代码中会先拿到当前线程,然后依据当前线程拿到属于当前线程的一个 map 键值对表,这个 map 才是关键所在,然后将 this 也就是当前这个 ThreadLocal 对象作为 key,将 aaa 作为 value 存储进 map 中,因为这个 map 是做到线程隔离的,所以可以发现我们虽然把 ThreadLocal 弄成静态,并且通过threadLocal.set("aaa")方式存储数据,但是多线程使用中也不会造成数据串扰

举例

A 类中大部分数据是多线程通用的,但是有一个数据是多线程区分的,跑多线程时候,每跑一个线程就会new A()一次

public class A{
	private String param1 = "a";
	private static String param2 = "b";
	private static String param3 = "c";
	public static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    // 一些操作之后将某个变量保存进线程本地存储中
	public void operate(String str){
		String string = str + Math.random();
		threadLocal.set(String);
	}
	
	// 提取变量
	public String take(){
		return threadLocal.get();
	}
}

试想一下要是 ThreadLocal 不是 static,那么每次创建 A 的时候,产生都是新的 ThreadLocal,根据其底层原理,其底层是一个线程有关的 map,key 是 ThreadLocal 对象,因为 ThreadLocal 要是不弄成静态,也就是说每次存进 map 时候 key 都不同,这样就变成了存了好几个 key-value 到一个线程相关的 map 中,然后我取的时候还要找到指定的 ThreadLocal 对象再调用其 get 方法才能取,但同样功能上也做到了线程隔离
上述例子中,b 和 c 多线程中是公用的,一般我会遇到每起一个线程会 new 一个 A,这个 A 中的 a 就成了线程隔离的变量了,c 也是线程隔离的变量

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

abcnull

您的打赏是我创作的动力之一

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值