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 ...
随机推荐
- c语言:解释程序和编译程序
编译程序和解释程序是程序执行的两种不同执行方式. 编译程序:编译程序的功能是把用高级语言书写的源程序翻译成与之等价的目标程序.编译过程划分成词法分析.语法分析.语义分析.中间代码生成.代码优化和目标代 ...
- python 最大公约数 最小公倍数
def gongyueshu(m,n): if m<n: m,n=n,m elif m==n: return m if m/n==int(m/n): return n else: for i i ...
- Qt Model/view 小实例 文件目录浏览器
1. 文件目录浏览器 直接在main.cpp文件中添加下列代码 #include "mainwindow.h" #include <QApplication> #inc ...
- java02动手动脑
1 编写一个方法,生成一千个随机数,用ppt提供的纯随机数发生器. 做这个题目时,看到老师已经给出Xn+1=(aXn+c) mod Integer.MAX_VALUE;给出了公式自然就算法明了. 我想 ...
- Java基础00-数组9
1. 数组定义格式 1.1 数组概述 1.2 什么是数组 1.3 数组定义格式 推荐使用第一种格式,因为第一种格式读法比较顺畅. 2. 数组初始化之动态初始化 2.1 数组初始化概述 2.2 数组初始 ...
- Easyui动态添加控件无法渲染 $.parser.parse()无效
本文链接:https://blog.csdn.net/huangbaokang/article/details/78367553动态添加easyui控件<input class="ea ...
- 超详细!搭建本地大数据研发环境(16G内存+CDH)
工欲善其事必先利其器,在经过大量的理论学习以后,需要有一个本地的研发环境来进行练手.已经工作的可以不依赖于公司的环境,在家也可以随意的练习.而自学大数据的同学,也可以进行本地练习,大数据是一门偏实践的 ...
- odoo14通过命令行启动以及报错进不去系统问题解决办法
一.通过CMD命令界面启动odoo:进入odoo-bin目录下:执行 python odoo-bin -c odoo.conf 二.pycharm配置自动安装升级模块:-c E:\odoo14\od ...
- SpringBoot Aop 详解和多种使用场景
前言 aop面向切面编程,是编程中一个很重要的思想本篇文章主要介绍的是SpringBoot切面Aop的使用和案例 什么是aop AOP(Aspect OrientedProgramming):面向切面 ...
- g6踩坑
1. 当父元素有transform: scale()时,有鼠标定位不准确的问题 // 开启支持css缩放,智能保证基本的准确,很多情况还是有问题 graph.get('canvas').set('su ...