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~


https://github.com/dotnet/coreclr/blob/9773db1e7b1acb3ec75c9cc0e36bd62dcbacd6d5/src/System.Private.CoreLib/shared/System/Threading/ThreadLocal.cs

C# ThreadLocal源码追踪的更多相关文章

  1. 并发编程(四)—— ThreadLocal源码分析及内存泄露预防

    今天我们一起探讨下ThreadLocal的实现原理和源码分析.首先,本文先谈一下对ThreadLocal的理解,然后根据ThreadLocal类的源码分析了其实现原理和使用需要注意的地方,最后给出了两 ...

  2. Java多线程9:ThreadLocal源码剖析

    ThreadLocal源码剖析 ThreadLocal其实比较简单,因为类里就三个public方法:set(T value).get().remove().先剖析源码清楚地知道ThreadLocal是 ...

  3. Java多线程学习之ThreadLocal源码分析

    0.概述 ThreadLocal,即线程本地变量,是一个以ThreadLocal对象为键.任意对象为值的存储结构.它可以将变量绑定到特定的线程上,使每个线程都拥有改变量的一个拷贝,各线程相同变量间互不 ...

  4. Java并发编程之ThreadLocal源码分析

    ## 1 一句话概括ThreadLocal<font face="微软雅黑" size=4>  什么是ThreadLocal?顾名思义:线程本地变量,它为每个使用该对象 ...

  5. ThreadLocal源码解读

    1. 背景 ThreadLocal源码解读,网上面早已经泛滥了,大多比较浅,甚至有的连基本原理都说的很有问题,包括百度搜索出来的第一篇高访问量博文,说ThreadLocal内部有个map,键为线程对象 ...

  6. 源码追踪,解决Could not locate executable null\bin\winutils.exe in the Hadoop binaries.问题

    在windows系统本地运行spark的wordcount程序,会出现一个异常,但不影响现有程序运行. >>提君博客原创  http://www.cnblogs.com/tijun/  & ...

  7. ThreadLocal详解,ThreadLocal源码分析,ThreadLocal图解

    本文脉路: 概念阐释 ---->  原理图解  ------> 源码分析 ------>  思路整理  ----> 其他补充. 一.概念阐述. ThreadLocal 是一个为 ...

  8. Saiku登录源码追踪.(十三)

    Saiku登录源码追踪呀~ >>首先我们需要debug跟踪saiku登录执行的源码信息 saiku源码的debug方式上一篇博客已有说明,这里简单介绍一下 在saiku启动脚本中添加如下命 ...

  9. 【JAVA】ThreadLocal源码分析

    ThreadLocal内部是用一张哈希表来存储: static class ThreadLocalMap { static class Entry extends WeakReference<T ...

随机推荐

  1. [刘阳Java]_MySQL数据优化总结_查询备忘录

    数据库优化是在后端开发中必备技能,今天写一篇MySQL数据优化的总结,供大家看看 一.MySQL数据库优化分类 我们通过一个图片形式来看看数据优化一些策略问题 不难看出,优化有两条路可以选择:硬件与技 ...

  2. Gradle入门第一集【下载,安装和测试】

    参考:https://www.cnblogs.com/panchanggui/p/9394760.html 1,http://services.gradle.org/distributions/链接下 ...

  3. python -- 程序结构

    一.程序结构 • 定义python文件的头部模板:在File->Settings->Editor->File and Code Templates->Python script ...

  4. RHEL7配置端口转发和地址伪装

    说明:这里是Linux服务综合搭建文章的一部分,本文可以作为Linux上使用firewalld做端口转发和地址伪装以及外网访问内网的参考. 注意:这里所有的标题都是根据主要的文章(Linux基础服务搭 ...

  5. Springboot+Mybatis+小程序

    思维导图: 项目效果图 一览界面: 新增界面:

  6. 福昕foxit phantom pdf高级编辑器企业版10.1 pro安装破解教程

    本文提供福昕foxit phantom pdf高级编辑器企业版10.1的安装教程.pj教程,可以使用全部功能,注意的是此方法对个人版无效. 没有必要再尝试别的文章,仅看这一篇即可!别的文章亲测是通过修 ...

  7. Android开发在Activity外申请权限调用相机打开相册

    问题描述: 最近在项目中遇到一个需要调用相册和打开相机的需求,但是,在Android 6.0以后,调用相册属于危险权限,需要开发者动态获取,这就意味着我们申请权限是与Activity绑定的,但如果一个 ...

  8. Python实用案例,Python脚本,Python实现每日更换“必应图片”为“桌面壁纸”

    往期回顾 Python实现自动监测Github项目并打开网页 Python实现文件自动归类 Python实现帮你选择双色球号码 前言: 今天我们就利用python脚本实现每日更换"必应图片& ...

  9. 云服务器是什么?ECS、BCC、CVM...

    什么是云服务器?云服务器有哪些优势?能用来干什么? 很多人不太了解云服务器的定义和用途. 云服务器是一种简单高效.处理能力可弹性伸缩的计算服务,帮助用户快速构建更稳定.安全的应用,提升运维效率,降低 ...

  10. SpringCloud升级之路2020.0.x版-7.从Bean到SpringCloud

    本系列为之前系列的整理重启版,随着项目的发展以及项目中的使用,之前系列里面很多东西发生了变化,并且还有一些东西之前系列并没有提到,所以重启这个系列重新整理下,欢迎各位留言交流,谢谢!~ 在理解 Spr ...