博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
.NET:线程本地存储、调用上下文、逻辑调用上下文
阅读量:6695 次
发布时间:2019-06-25

本文共 4360 字,大约阅读时间需要 14 分钟。

背景

在多线程环境,如果需要将实例的生命周期控制在某个操作的执行期间,该如何设计?经典的思路是这样的:作为参数向调用栈传递,如: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 ExecutionContextStudy10 {11     class ThreadDataSlotTest12     {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 ExecutionContextStudy10 {11     class CallContextTest12     {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 ExecutionContextStudy10 {11     class ExecutionContextTest12     {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 容器自定义生命周期管理模型。

 

转载地址:http://ulpoo.baihongyu.com/

你可能感兴趣的文章
【Java自学笔记系列:数组】
查看>>
Django之url路由
查看>>
二叉树的所有路径
查看>>
java反射机制的原理与简单使用
查看>>
CentOs
查看>>
Dockerfile编写(备份)
查看>>
解决Ubuntun 12.04编译Mesa10.3 WARNING: 'aclocal-1.14' is missing on your system
查看>>
junit设计模式--适配器模式
查看>>
关于门诊处方的一次计量保留小数点的问题
查看>>
Java常见面试题汇总(一)
查看>>
JAVA如何实现深拷贝
查看>>
[sphinx]中文语言模型训练
查看>>
CHIL-SQL-NOT NULL 约束
查看>>
最短路径 - 弗洛伊德(Floyd)算法
查看>>
FlasCC例子研究之Drawing补充
查看>>
省市县结合身份证号6位码的三级联动
查看>>
common.js
查看>>
Oracle(转换函数)
查看>>
构建高性能数据库缓存之redis(二)
查看>>
sdk 升级,search path,
查看>>