ThreadLocal源码:存取数据流程

本文详细探讨ThreadLocal的源码,包括其存储数据结构、内存管理和存取过程。ThreadLocal通过在每个线程内部维护一个Map,以线程局部变量的形式实现数据隔离,提高多线程环境下的效率。文中分析了ThreadLocalMap中Entry数组的环形结构、弱引用避免内存泄露的策略以及散列查找方法。同时,介绍了ThreadLocal.set()和ThreadLocal.get()的方法实现,以及ThreadLocalMap的创建和初始化过程。

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

1、回顾ThreadLocal

之前写过一篇ThreadLocal简单使用的日志,里面展示了一个例子,以及get()和set()方法的源码。ThreadLocal是不同于锁的方式解决了多线程访问临界资源的安全性问题,且某些场景下效率更高。最近也在读ThreadLocal的源码,发现很多知识点上一篇日志没有兼顾到(例如令我印象深刻的是线程中的ThreadLocalMap中维护的Entry[]数组是环形结构,数组的扩容阈值和用到了哈希函数和线性探测方式,都是当初学习数据结构与算法时满满的回忆哈哈),所以现在决定再写一篇自己对ThreadLocal学习总结的日志。

ThreadLocal的作用是把数据副本放入到该ThreadLocal实例所在的线程的Map中,Map中的key对应ThreadLocal的实例对象,value则对应我们放进去的数据。因为Map只属于当前线程,它是Thread类内部的一个实例变量,所以,只有当前线程可以访问到这个Map,对这个Map里面的数据做修改,所以可以保证多线程修改同一数据的安全性问题,通过隔离的方法,即把数据副本放入到各自线程的Map中去,各个线程修改自己的副本数据。

使用ThreadLocal还有一个很大的好处是,提高了效率。为了保证数据的安全性,我们很自然地会想到加锁,在对临界资源数据做修改前先加锁,修改操作完成后再释放锁,这种做法的确保护了数据的安全,但效率不高,因为一旦一个线程在修改临界资源时加锁了,那么其他想要访问这个临界资源的线程便不得不停下来,等待锁的释放,试想假如有大量线程因为等待锁而被阻塞,肯定导致整体效率不高。使用ThreadLocal则可以解决效率问题,正如上面所说,把数据副本放入到自己线程的Map中修改,线程之间互不干扰,也就不会有互相等待的问题了。

 

2、存储数据结构

2.1 ThreadLocalMap中的成员变量

    // ThreadLocalMap的初始大小capacity
	private static final int INITIAL_CAPACITY = 16;
	// Entry数组
	private Entry[] table;
	// Entry数组的大小
	private int size = 0;
	// Entry数组下一次扩容的阈值
	private int threshold;

可以看到,在线程的ThreadLocalMap中,有一个Entry[]数组,用来存放数据副本,这个Entry[]数组就是我们说的线程里的Map。前面说到,每一个Thread都有各自的Map,ThreadLocal类只是把数据放入到所在线程的Map中,然后Map中的key对应ThreadLocal类的实例,value则对应存储数据。但是注意,这个Map并不是并不是我们java.util.map包中的map,它只是形式上像Map,因为有key和value。那么这个key和value是怎么对应的呢?来看看这个存储在线程中的ThreadLocalMap,它的存储结点Entry是怎样定义的:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值