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语言:结果不理解
#include <stdio.h> int main() { int a;float b; scanf("a=%d,b=%f",&a,&b); pri ...
- .netcore第三方登录授权:10分钟急速接入
前言 很多对外应用的开发都考虑接入第三方登录来提高用户的体验感,避免用户进行繁琐的注册登录(登录后的完善资料必不可免). 而QQ.微信.支付宝.淘宝.微博等应用就是首选目标(无他,用户群体大,支持发开 ...
- HelloWord!
HelloWorld 1.新建一个文件夹,存放代码 2.新建一个java文件后缀为.java Hello.java (注意后缀 如系统没打开显示后缀需要打开) 3.编写HelloWorld代码 (建议 ...
- springboot-5-持久层技术
整合mybatis 流程: 导入依赖: 除了mybaits还有mysql和jdbc依赖 <!--mybatis--> <dependency> <groupId>o ...
- 微信小程序云开发-云存储的应用-识别通用印刷体
一.准备工作 1.创建云函数identify 2.云函数identify中index.js代码 1 // 云函数入口文件 2 const cloud = require('wx-server-sdk' ...
- Web的工作原理(二)
1.工作过程:如下图所示描述了Web的工作原理. (1) 用户打开计算机(客户机),启动浏览器程序,并在浏览器中指定一个URL(Uniform Resource Locator,统一资源定位器),浏览 ...
- GC垃圾回收机制详解
JVM堆相关知识 为什么先说JVM堆? JVM的堆是Java对象的活动空间,程序中的类的对象从中分配空间,其存储着正在运行着的应用程序用到的所有对象.这些对象的建立方式就是那些new一类的操作 ...
- js学习笔记之自调用函数、闭包、原型链
自调用函数 var name = 'world!'; // console.log(typeof name) (function () { console.log(this.name, name, ...
- mongo-express 远程代码执行漏洞(CVE-2019-10758)
影响版本 mongo-express 0.53.0 POST /checkValid HTTP/1.1 Host: 192.168.49.2:8081 Accept-Encoding: gzip, d ...
- Mariadb常用管理操作
一 Mariadb常用管理操作 纯干货,没有一点废话,全是使用频率最高和常用的操作,运维必不可少的基础资料. 1.1 创建数据库 >create database <db_name> ...