.NET中的线程本地存储(TLS)与AsyncLocal(一)
一、TLS
线程本地存储(Thread Local Storage),字面意思就是专属某个线程的存储空间。变量大体上分为全局变量和局部变量,一个进程中的所有线程共享地址空间,这个地址空间被划分为几个固有的区域,比如堆栈区,全局变量区等,全局变量存储在全局变量区,虚拟地址固定;局部变量存储在堆栈区,虚拟地址不固定。每个线程都有自己的栈空间,局部变量就存储在栈空间里面,虽然这个局部变量是与线程相联系的,但是这个局部变量不能在不同的函数栈中互相直接访问,但TLS可以,概括来讲,TLS是属于线程的“局部变量”,作用域为线程作用域,而不像全局变量为全局作用域,局部变量为局部作用域,因为这个变量独属于这个线程,所以这个变量是线程安全的。
二、.NET中相关的类——ThreadLocal
代码更直观,请看下面的代码:
1 static void Main(string[] args)
2 {
3 ThreadLocal<int> threadLocal = new ThreadLocal<int>();
4 //在主线程这个变量值为1
5 threadLocal.Value = 1;
6 new Thread(() => Console.WriteLine($"托管线程ID:{Thread.CurrentThread.ManagedThreadId} 值为:{threadLocal.Value++}")).Start();
7 new Thread(() => Console.WriteLine($"托管线程ID:{Thread.CurrentThread.ManagedThreadId} 值为:{threadLocal.Value++}")).Start();
8 new Thread(() => Console.WriteLine($"托管线程ID:{Thread.CurrentThread.ManagedThreadId} 值为:{threadLocal.Value++}")).Start();
9 Console.WriteLine($"主线程ID:{Thread.CurrentThread.ManagedThreadId} 值为:{threadLocal.Value}");
10 }
输出结果如下:

可以看见每个这个变量的值对于每个线程来说都是独立的,一个线程对这个变量的修改只会影响本线程的读取,每个线程都有一份拷贝。
有什么用呢?或者使用场景是什么呢?我觉得就是一句话——当每个线程都需要一个唯一的变量的时候。
比如早期版本的ASP.NET,每个线程处理一个Http请求,在处理这个Http请求的线程中,这个HttpContext在这个线程中是唯一的,所以在每个函数中都可以调用HttpContext.Current获得当前Http请求上下文对象,为了加深理解,请看下面的代码
1 public class ConsoleContext
2
3 {
4
5 private static ThreadLocal<ConsoleContext> _tlsCCT = new ThreadLocal<ConsoleContext>();
6
7 private string _consoleName;
8
9 public string ConsoleName { get => _consoleName; }
10
11 public static ConsoleContext Current { get => _tlsCCT.Value; }
12
13 public ConsoleContext(string consoleName)
14
15 {
16
17 _consoleName = consoleName;
18
19 _tlsCCT.Value = this;
20
21 }
22
23 public static void ResetContext() => _tlsCCT.Value = null;
24
25 }
26
27 public static void Excute()
28
29 {
30
31 Thread.Sleep(1000 * new Random(DateTime.Now.Millisecond).Next(5,10));
32
33 Console.WriteLine("进入PrintName()");
34
35 PrintName();
36
37 }
38
39 public static void PrintName()
40
41 {
42
43 var name = ConsoleContext.Current.ConsoleName;
44
45 Console.WriteLine($"当前托管线程ID:{Thread.CurrentThread.ManagedThreadId} name:{name}");
46
47 }
48
49 static void Main(string[] args)
50
51 {
52
53 while (true)
54
55 {
56
57 var name = Console.ReadLine();
58
59 ThreadPool.QueueUserWorkItem(state =>
60
61 {
62
63 Console.WriteLine($"当前托管线程ID:{Thread.CurrentThread.ManagedThreadId} name:{name}");
64
65 new ConsoleContext(name);
66
67 Excute();
68
69 ConsoleContext.ResetContext();
70
71 });
72
73 }
74
75 }
简单来说,我模拟了一个Web服务器的行为,监听请求(在这里是监听键盘输入),若没有请求过来,服务器程序阻塞,若有请求过来(在这里是键盘输入),服务器响应请求,生成当前请求上下文,并生成一个TLS变量,然后执行Excute函数(相当HttpContext流入处理管道),最后清空TLS变量中的值,因为该线程是线程池中的线程,会被复用用于处理其他请求,不清空TLS会生成脏数据。
.NET中的线程本地存储(TLS)与AsyncLocal(一)的更多相关文章
- 线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理
原文链接地址:http://www.cppblog.com/Tim/archive/2012/07/04/181018.html 本文为线程本地存储TLS系列之分类和原理. 一.TLS简述和分类 我们 ...
- 线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理
本文为线程本地存储TLS系列之分类和原理. 一.TLS简述和分类 我们知道在一个进程中,所有线程是共享同一个地址空间的.所以,如果一个变量是全局的或者是静态的,那么所有线程访问的是同一份,如果某一个线 ...
- Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic
Atitit usrqbg1821 Tls 线程本地存储(ThreadLocal Storage 规范标准化草案解决方案ThreadStatic 1.1. ThreadLocal 设计模式1 1.2. ...
- 线程本地存储(Thread Local Storage, TLS)简单分析与使用
在多线程编程中, 同一个变量, 如果要让多个线程共享访问, 那么这个变量可以使用关键字volatile进行声明; 那么如果一个变量不想使多个线程共享访问, 那么该怎么办呢? 呵呵, 这个办法就是TLS ...
- 线程本地存储(动态TLS和静态TLS)
线程本地存储(TLS) 对于多线程应用程序,如果线程过于依赖全局变量和静态局部变量就会产生线程安全问题.也就是一个线程的使用全局变量可能会影响到其他也使用此全局变量的线程,有可能会造成一定的错误,这可 ...
- ThreadLocal(线程本地存储)
1. ThreadLocal,即线程本地变量或线程本地存储. threadlocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的 ...
- 线程本地存储 ThreadLocal
线程本地存储 · 语雀 (yuque.com) 线程本地存储提供了线程内存储变量的能力,这些变量是线程私有的. 线程本地存储一般用在跨类.跨方法的传递一些值. 线程本地存储也是解决特定场景下线程安全问 ...
- Chrome扩展开发之三——Chrome扩展中的数据本地存储和下载
目录: 0.Chrome扩展开发(Gmail附件管理助手)系列之〇——概述 1.Chrome扩展开发之一——Chrome扩展的文件结构 2.Chrome扩展开发之二——Chrome扩展中脚本的运行机制 ...
- .NET:线程本地存储、调用上下文、逻辑调用上下文
.NET:线程本地存储.调用上下文.逻辑调用上下文 目录 背景线程本地存储调用上下文逻辑调用上下文备注 背景返回目录 在多线程环境,如果需要将实例的生命周期控制在某个操作的执行期间,该如何设计?经典的 ...
- C# 线程本地存储 调用上下文 逻辑调用上下文
线程本地存储 using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleAppTest ...
随机推荐
- CDS标准视图:维护计划员组 I_MAINTENANCEPLANNERGROUP
视图名称:维护计划员组 I_MAINTENANCEPLANNERGROUP 视图类型:基础视图 视图代码: 点击查看代码 @EndUserText.label: 'Maintenance Planne ...
- VulNyx - Mail 靶机
扫描靶机 发现22 和 80端口 访问80端口 发现id=1 和2 时都会有回显 dirsearch -u http://http://192.168.200.39 访问这个1 和 2的路径 发现竟然 ...
- Codeforces Round 961 (Div. 2)
题目链接:Codeforces Round 961 (Div. 2) 总结:B1wa两发可惜,C出得有点小慢. A. Diagonals fag:贪心 Description:给定一个\(n * n\ ...
- h5使用vue-photo-preview 做全屏预览
h5页面使用全屏预览 最近需要在微信小程序中跳转到h5页面 在h5页面中需要进行图片预览展示 由于没有使用第三方的组件库. 只能手写,但是时间很紧张. 所以只能够寻找第三方的插件 vue-photo- ...
- 两种方式让你用Python轻松在RDKX5上部署推理
作者:SkyXZ CSDN:SkyXZ--CSDN博客 博客园:SkyXZ - 博客园 宿主机环境:WSL2-Ubuntu22.04+Cuda12.6.D-Robotics-OE 1.2.8.Ubun ...
- 浅谈ChatGPT在云计算资源调度的应用
本文分享自天翼云开发者社区<浅谈ChatGPT在云计算资源调度的应用>,作者:张****兵 一.ChatGPT技术原理 ChatGPT 是基于 GPT(Generative Pre-tra ...
- JAVA基础环境配置指南(简洁版)
1.安装JDK 官网下载后直接安装 配置环境变量: 添加 JAVA_HOME 变量名:JAVA_HOME 变量值:C:\Program Files (x86)\Java\jdk1.8.0_91 // ...
- 记一次golang项目context引发的OOM故障
之前写过一篇一种基于etcd实践节点自动故障转移的思路, 程序经历过一次线上进程内存持续上涨终OOOM的小事故, 本次技术复盘导致本次内存泄露的完整起因. 提炼代码: 业务函数etcdWatchLoo ...
- Eclipse各历史版本所需的最低JDK版本统计
Eclipse 版本名称 Version 发布时间 最低支持的jdk Kepler 4.3 2013.06 Java 6 Luna 4.4 2014.06.25 Java 7 Mars 4.5 201 ...
- 摸鱼日历,新闻简报等一些工作摸鱼日历API接口合集分享
摸鱼人日历API接口 请求示例(图片输出): https://moyu.qqsuu.cn 请求示例(JSON输出):[推荐] https://moyu.qqsuu.cn/?type=json 调用示例 ...