在 .NET 中,AsyncLocal<T> 是一个非常特殊的结构。它的最大特点是:在异步调用或线程切换的过程中,可以为每个逻辑上下文(ExecutionContext)保存独立的值。
🌟 与其他结构相比,AsyncLocal<T> 的独特之处在于:
- 如果某个线程(或异步上下文)在创建新的线程或任务之前,已经为
AsyncLocal<T>设置了值, - 那么 新的线程或任务会“继承”这个值的一份副本。
🔁 值的“拷贝”是怎样的?
-
实际上,这个“拷贝”不是深拷贝,而是浅拷贝。
-
所以:
- 如果
T是不可变类型(如string,int),那么新的线程获得的是该值的一个副本,修改不会影响原线程的值。 - 如果
T是可变引用类型(如List<string>,StringBuilder),那么新的线程获得的是对该对象的引用,修改内容会影响原线程的值。
- 如果
📌 示例说明:
假设我们使用 AsyncLocal<StringBuilder>:
AsyncLocal<StringBuilder> context = new AsyncLocal<StringBuilder>();
context.Value = new StringBuilder("Hello");
Thread newThread = new Thread(() =>
{
// 此处 context.Value 是原线程中的 StringBuilder 实例的引用
context.Value.Append(" World");
});
newThread.Start();
newThread.Join();
Console.WriteLine(context.Value.ToString()); // 输出 "Hello World"
✅ 原因:
StringBuilder是引用类型。- 虽然线程上下文中的
AsyncLocal<T>值是“拷贝”过来的,但它是“浅拷贝”,仍然引用同一个StringBuilder实例。
📌 如果换成不可变类型,如 string:
AsyncLocal<string> context = new AsyncLocal<string>();
context.Value = "Hello";
Thread newThread = new Thread(() =>
{
context.Value = "World"; // 只影响新线程自己的上下文值
});
newThread.Start();
newThread.Join();
Console.WriteLine(context.Value); // 输出 "Hello"
✅ 原因:
string是不可变引用类型。- 新线程改变
context.Value后,不影响原始线程中的值。
🔍 总结:
| 类型 | 是否可变 | 新线程修改是否影响原线程 |
|---|---|---|
string, int | 否(不可变) | ❌ 不影响 |
List<string>, StringBuilder | 是(可变) | ✅ 会影响(引用相同) |
815

被折叠的 条评论
为什么被折叠?



