C# ThreadLocal源码追踪
ThreadLocal
字段成员:
private Func<T>? _valueFactory;
一个获取默认值的委托 不同线程共享此成员。
[ThreadStatic]
private static LinkedSlotVolatile[]? ts_slotArray;
ThreadStatic特性,这不就是我们熟悉的ThreadStaticAttribute吗,
所以ThreadLocal 就是一个ThreadStatic的封装类,简化了tls操作
[ThreadStatic]
private static FinalizationHelper? ts_finalizationHelper;
见名思义,用于释放的帮助类
private int _idComplement;
Slot ID of this ThreadLocal<instance.
这个ThreadLocal<>实例的槽ID。
We store a bitwise complement of the ID (that is ~ID), which allows us to distinguish
我们存储ID的位补码(即~ID),这使我们能够区分
between the case when ID is 0 and an incompletely initialized object, either due to a thread abort in the constructor, or
在ID为0的情况和未完全初始化的对象之间,原因可能是构造函数中的线程中止,也可能是
possibly due to a memory model issue in user code.
可能是由于用户代码中的内存模型问题。
用于区分是否初始化。
private volatile bool _initialized;
表示对象是否完全初始化..
private volatile bool _initialized;
是否初始化-构造函数
private static readonly IdManager s_idManager = new IdManager();
IdManager assigns and reuses slot IDs.
IdManager分配和重用插槽id。
Additionally, the object is also used as a global lock.
此外,该对象还用作全局锁。
private LinkedSlot? _linkedSlot = new LinkedSlot(null);
伪头节点
private bool _trackAllValues;
是否支持Values属性
方法
private void Initialize(Func<T>? valueFactory, bool trackAllValues)
{
_valueFactory = valueFactory;
_trackAllValues = trackAllValues;
// Assign the ID and mark the instance as initialized. To avoid leaking IDs, we assign the ID and set _initialized
// in a finally block, to avoid a thread abort in between the two statements.
try { }
finally
{
_idComplement = ~s_idManager.GetId();
// As the last step, mark the instance as fully initialized. (Otherwise, if _initialized=false, we know that an exception
// occurred in the constructor.)
_initialized = true;
}
}
初始化方法,所有构造通过此方法初始化。
查看IdManager的GetId方法:
internal int GetId()
{
List<bool> freeIds = this.m_freeIds;
lock (freeIds)
{
int nextIdToTry = this.m_nextIdToTry;
while (nextIdToTry < this.m_freeIds.Count)
{
if (this.m_freeIds[nextIdToTry])
{
break;
}
nextIdToTry++;
}
if (nextIdToTry == this.m_freeIds.Count)
{
this.m_freeIds.Add(false);
}
else
{
this.m_freeIds[nextIdToTry] = false;
}
this.m_nextIdToTry = nextIdToTry + 1;
return nextIdToTry;
}
}
具体就不说明了,类似于数据库中的自增标识
注:由于ThreadLocal为泛型类,仅当构造同类型的ThreadLocal才会触发自增
这里我们也可以知道为何需要一个LinkedSlotVolatile数组
当线程中存在多个ThreadLocal即存在多个泛型类型相同的ThreadLocal,就需要使用数组进行存储,而_idComplement就是充当一个数组下标的功能
public T Value
{
get
{
LinkedSlotVolatile[]? slotArray = ts_slotArray;
LinkedSlot? slot;
int id = ~_idComplement;
//
// Attempt to get the value using the fast path
//
if (slotArray != null // Has the slot array been initialized?
&& id >= 0 // Is the ID non-negative (i.e., instance is not disposed)?
&& id < slotArray.Length // Is the table large enough?
&& (slot = slotArray[id].Value) != null // Has a LinkedSlot object has been allocated for this ID?
&& _initialized // Has the instance *still* not been disposed (important for a race condition with Dispose)?
)
{
// We verified that the instance has not been disposed *after* we got a reference to the slot.
// This guarantees that we have a reference to the right slot.
//
// Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read
// will not be reordered before the read of slotArray[id].
return slot._value;
}
return GetValueSlow();
}
set
{
LinkedSlotVolatile[]? slotArray = ts_slotArray;
LinkedSlot? slot;
int id = ~_idComplement;
// Attempt to set the value using the fast path
if (slotArray != null // Has the slot array been initialized?
&& id >= 0 // Is the ID non-negative (i.e., instance is not disposed)?
&& id < slotArray.Length // Is the table large enough?
&& (slot = slotArray[id].Value) != null // Has a LinkedSlot object has been allocated for this ID?
&& _initialized // Has the instance *still* not been disposed (important for a race condition with Dispose)?
)
{
// We verified that the instance has not been disposed *after* we got a reference to the slot.
// This guarantees that we have a reference to the right slot.
//
// Volatile read of the LinkedSlotVolatile.Value property ensures that the m_initialized read
// will not be reordered before the read of slotArray[id].
slot._value = value;
}
else
{
SetValueSlow(value, slotArray);
}
}
}
如果slotArray中有值就操作slotArray ,否则就
写-更新slotArray
读-从_valueFactory 取值
到这里就差不多了,over~
C# ThreadLocal源码追踪的更多相关文章
- 并发编程(四)—— ThreadLocal源码分析及内存泄露预防
今天我们一起探讨下ThreadLocal的实现原理和源码分析.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两 ...
- Java多线程9:ThreadLocal源码剖析
ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...
- Java多线程学习之ThreadLocal源码分析
0.概述 ThreadLocal,即线程本地变量,是一个以ThreadLocal对象为键.任意对象为值的存储结构.它可以将变量绑定到特定的线程上,使每个线程都拥有改变量的一个拷贝,各线程相同变量间互不 ...
- Java并发编程之ThreadLocal源码分析
## 1 一句话概括ThreadLocal<font face="微软雅黑" size=4> 什么是ThreadLocal?顾名思义:线程本地变量,它为每个使用该对象 ...
- ThreadLocal源码解读
1. 背景 ThreadLocal源码解读,网上面早已经泛滥了,大多比较浅,甚至有的连基本原理都说的很有问题,包括百度搜索出来的第一篇高访问量博文,说ThreadLocal内部有个map,键为线程对象 ...
- 源码追踪,解决Could not locate executable null\bin\winutils.exe in the Hadoop binaries.问题
在windows系统本地运行spark的wordcount程序,会出现一个异常,但不影响现有程序运行. >>提君博客原创 http://www.cnblogs.com/tijun/ & ...
- ThreadLocal详解,ThreadLocal源码分析,ThreadLocal图解
本文脉路: 概念阐释 ----> 原理图解 ------> 源码分析 ------> 思路整理 ----> 其他补充. 一.概念阐述. ThreadLocal 是一个为 ...
- Saiku登录源码追踪.(十三)
Saiku登录源码追踪呀~ >>首先我们需要debug跟踪saiku登录执行的源码信息 saiku源码的debug方式上一篇博客已有说明,这里简单介绍一下 在saiku启动脚本中添加如下命 ...
- 【JAVA】ThreadLocal源码分析
ThreadLocal内部是用一张哈希表来存储: static class ThreadLocalMap { static class Entry extends WeakReference<T ...
随机推荐
- VS2013产品密钥
VS2013 产品密钥 – 所有版本 Visual Studio Ultimate 2013 KEY(密钥):BWG7X-J98B3-W34RT-33B3R-JVYW9 Visual Studio ...
- SQL2008 合并多个结构相同的表的所有数据到新的表
select * into tikua from (select * from tiku20210303 union all select * from tiku) a
- 添加Lombok插件后调用Setter或Getter方法IDEA编译错误
虽然添加Lombok插件,但是调用Setter或Getter方法IDEA编译错误,主要原因如下 解决办法:
- Tomcat网站根目录设置
直接将war放入到webapps目录下 修改server.xml文件,在Host节点下添加如下代码 <Context path="/" docBase="web&q ...
- 痞子衡嵌入式:了解i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是i.MXRTxxx系列ROM中灵活的串行NOR Flash启动硬复位引脚选择. 关于 i.MXRT 系列 BootROM 中串行 NOR ...
- Hive——连接方式
Hive--连接方式 一.CLI连接 直接通过CLI连接hive,进行相关hive sql 操作. 直接使用 hive-1.1.0-cdh5.7.0/bin/hive 命令即可 hive> ...
- 《面试八股文》之 Redis 16卷
微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. redis 作为 ...
- Scrapy入门到放弃03:理解settings配置,监控Scrapy引擎
前言 代码未动,配置先行.本篇文章主要讲述一下Scrapy中的配置文件settings.py的参数含义,以及如何去获取一个爬虫程序的运行性能指标. 这篇文章无聊的一匹,没有代码,都是配置化的东西,但是 ...
- HashSet 和 HashMap 的比较
HashMap 和 HashSet 都是 collection 框架的一部分,它们让我们能够使用对象的集合.collection 框架有自己的接口和实现,主要分为 Set 接口,List 接口和 Qu ...
- GC Roots包含哪些
1.虚拟机栈中引用的对象 2.方法区中静态属性.常量引用的对象 3. 本地方法栈中引用的对象 4. 被Synchronized锁持有的对象 5. 记录当前被加载类的SystemDictionary 6 ...