.NET:线程本地存储、调用上下文、逻辑调用上下文
.NET:线程本地存储、调用上下文、逻辑调用上下文
背景返回目录
在多线程环境,如果需要将实例的生命周期控制在某个操作的执行期间,该如何设计?经典的思路是这样的:作为参数向调用栈传递,如:CommandExecuteContext、HttpContext等。好在很多平台都提供线程本地存储这种东西,下面介绍一下 .NET 提供的三种机制。
线程本地存储返回目录
代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using System.Runtime.Remoting;
8
9 namespace ExecutionContextStudy
10 {
11 class ThreadDataSlotTest
12 {
13 public static void Test()
14 {
15 for (var i = 0; i < 10; i++)
16 {
17 Thread.Sleep(10);
18
19 Task.Run(() =>
20 {
21 var slot = Thread.GetNamedDataSlot("test");
22 if (slot == null)
23 {
24 Thread.AllocateNamedDataSlot("test");
25 }
26
27 if (Thread.GetData(slot) == null)
28 {
29 Thread.SetData(slot, DateTime.Now.Millisecond);
30 }
31
32 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + Thread.GetData(slot));
33 });
34 }
35
36 Console.ReadLine();
37 }
38 }
39 }

结果

说明
如果使用了线程池,最好不要使用这种存储机制了,因为线程池可能不会释放使用过的线程,导致多次执行之间可能共享数据(可以每次执行前重置线程本地存储的数据)。
调用上下文返回目录
代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using System.Runtime.Remoting.Messaging;
8
9 namespace ExecutionContextStudy
10 {
11 class CallContextTest
12 {
13 public static void Test()
14 {
15 Console.WriteLine("测试:CallContext.SetData");
16 for (var i = 0; i < 10; i++)
17 {
18 Thread.Sleep(10);
19
20 Task.Run(() =>
21 {
22 if (CallContext.GetData("test") == null)
23 {
24 CallContext.SetData("test", DateTime.Now.Millisecond);
25 }
26
27 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));
28 });
29 }
30
31 Console.ReadLine();
32 }
33 }
34 }

结果

说明
由上图可以知道,每次执行的数据是完全隔离的,非常符合我们的期望。但是,如果我们期望调用期间又开启了一个子线程,如何让子线程访问父线程的数据呢?这就需要使用到:“逻辑调用上下文”。
逻辑调用上下文返回目录
代码

1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using System.Threading;
6 using System.Threading.Tasks;
7 using System.Runtime.Remoting.Messaging;
8
9 namespace ExecutionContextStudy
10 {
11 class ExecutionContextTest
12 {
13 public static void Test()
14 {
15 Console.WriteLine("测试:CallContext.SetData");
16 Task.Run(() =>
17 {
18 CallContext.SetData("test", "段光伟");
19 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));
20
21 Task.Run(() =>
22 {
23 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.GetData("test"));
24 });
25 });
26
27 Thread.Sleep(100);
28
29 Console.WriteLine("测试:CallContext.LogicalSetData");
30 Task.Run(() =>
31 {
32 CallContext.LogicalSetData("test", "段光伟");
33 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));
34
35 Task.Run(() =>
36 {
37 Console.WriteLine(Thread.CurrentThread.ManagedThreadId + ":" + CallContext.LogicalGetData("test"));
38 });
39
40 ExecutionContext.SuppressFlow();
41 Task.Run(() =>
42 {
43 Console.WriteLine("SuppressFlow 之后:" + CallContext.LogicalGetData("test"));
44 });
45
46 ExecutionContext.RestoreFlow();
47 Task.Run(() =>
48 {
49 Console.WriteLine("RestoreFlow 之后:" + CallContext.LogicalGetData("test"));
50 });
51 });
52
53 Console.ReadLine();
54 }
55 }
56 }

输出

说明
注意 ExecutionContext.SuppressFlow(); 和 xecutionContext.RestoreFlow();,它们分别能阻止传播和重置传播,默认是允许传播的。
备注返回目录
最常见的使用场景就是:为 Ioc 容器自定义生命周期管理模型。
.NET:线程本地存储、调用上下文、逻辑调用上下文的更多相关文章
- C# 线程本地存储 调用上下文 逻辑调用上下文
线程本地存储 using System; using System.Threading; using System.Threading.Tasks; namespace ConsoleAppTest ...
- 线程本地存储 ThreadLocal
线程本地存储 · 语雀 (yuque.com) 线程本地存储提供了线程内存储变量的能力,这些变量是线程私有的. 线程本地存储一般用在跨类.跨方法的传递一些值. 线程本地存储也是解决特定场景下线程安全问 ...
- 线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理
原文链接地址:http://www.cppblog.com/Tim/archive/2012/07/04/181018.html 本文为线程本地存储TLS系列之分类和原理. 一.TLS简述和分类 我们 ...
- 线程本地存储TLS(Thread Local Storage)的原理和实现——分类和原理
本文为线程本地存储TLS系列之分类和原理. 一.TLS简述和分类 我们知道在一个进程中,所有线程是共享同一个地址空间的.所以,如果一个变量是全局的或者是静态的,那么所有线程访问的是同一份,如果某一个线 ...
- ThreadLocal(线程本地存储)
1. ThreadLocal,即线程本地变量或线程本地存储. threadlocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或组件之间一些公共变量传递的 ...
- 线程本地存储(动态TLS和静态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 ...
- Java线程本地存储ThreadLocal
前言 ThreadLocal 是一种 无同步 的线程安全实现 体现了 Thread-Specific Storage 模式:即使只有一个入口,内部也会为每个线程分配特有的存储空间,线程间 没有共享资源 ...
随机推荐
- js中frame的操作问题
这里以图为例,在这里把frame之间的互相操作简单列为:1变量2方法3页面之间元素的互相获取. A 首先从 父(frameABC)------->子(frameA,frameB,frameC) ...
- bigdata_spark_源码修改_本地环境搭建_eclise
Eclipse 下开发调试环境的配置该小节中使用的各项工具分别为:mac (Windows 7)+Eclipse Java EE 4.4.2+Scala 2.10.4+Sbt 0.13.8+Maven ...
- hdu Max Sum Plus Plus(dp+滚动数组)
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1024 m为段,要深刻理解题意,并没有说是段与段要连接. 题解链接:http://blog.csdn.n ...
- oracle_利用闪回功能恢复数据
方便起见一般:执行如下即可不用往下看: ① 启用行移动功能 alter table tbl_a enable row movement; ② 闪回表数据到某个时间点 flashback table t ...
- jquery跨域请求解决方案(我们寻找,我还没有添加验证)
http://www.3lian.com/edu/2014/02-10/127921.html 本篇文章仅仅要是对jquery ajax跨域解决方法(json方式)进行了介绍,须要的朋友能够过来參考下 ...
- 去除win7 64位系统桌面图标小箭头
http://blog.csdn.net/pipisorry/article/details/24865195 在桌面新建一个文本文档 去除箭头.txt,把例如以下代码粘贴到文档中reg add &q ...
- Php设计模式(三):行为型模式part1
原文详见:http://www.ucai.cn/blogdetail/7023?mid=1&f=5 可以在线运行查看效果哦! 在上一篇我们讲了结构型模式,结构型模式是讨论类和对象的结构的.总共 ...
- Linux环境编程相关的文章
Linux环境编程相关的文章 好几年没有接触Linux环境下编程了,好多东西都有点生疏了.趁着现在有空打算把相关的一些技能重拾一下,顺手写一些相关的文章加深印象. 因为不是写书,也受到许多外部因素限制 ...
- fast-json.jar的用法
fast-json.jar 解析json数据:一种json数据解析方式是这种,点击这里下载jsonfast.jar+fastjsonAPI文档 [ { "id": 6378, &q ...
- log4e插件的安装和使用
1.首先下载log4e小工具.放入myeclipse10安装文件夹D:\Program Files (x86)\myEclipse10\MyEclipse Blue Edition 10\dropin ...