多线程同步就是在不同线程中访问同一个变量或共享资源,如果不使用线程同步,由于竞争的存在会使某些线程产生脏读或者是覆盖其它线程已写入的值,容易出现线程安全问题。另外让每个线程所访问的变量只属于各自线程自身所有,这就是线程本地变量。线程本地存储为了方便每个线程处理自己的状态而引入的一个机制。.
本文介绍.NET两种本地变量的使用:ThreadStatic,ThreadLocal<T>
一、使用ThreadStatic特性
ThreadStatic只支持静态字段,使用时将成员变量声明为static并打上[ThreadStatic]这个标记。如下:
[ThreadStatic]
public static int a;
[ThreadStatic]
public static int b;
public static void fun1()//定义方法1
{
a = 1;
b = 2;
Console.WriteLine($"a={a} [来自 fun1]");
Console.WriteLine($"b={b} [来自 fun1]");
}
public static void fun2()//定义方法2
{
a = 10;
b = 20;
Console.WriteLine($"a={a} [来自 fun2]");
Console.WriteLine($"b={b} [来自 fun2]");
}
public static void Run()
{
var thread1 = new Thread(fun1);
var thread2 = new Thread(fun2);
thread1.Start();//开始线程
thread2.Start();//开始线程
}
结果如下:
可以看到,a,b静态字段在两个线程中都是独立存储的,互相不会被修改。
二、使用ThreadLocal<T>关键字
ThreadLocal<T>是一种泛型化的本地变量存储机制 ,他在.NET 4才出现 。我们把上面的方法改造一下,如下:
public readonly ThreadLocal<int> a = new ThreadLocal<int>();
public readonly ThreadLocal<int> b = new ThreadLocal<int>();
public static void fun1()//定义方法1
{
a.Value= 1;
b.Value = 2;
Console.WriteLine($"a={a} [来自 fun1]");
Console.WriteLine($"b={b} [来自 fun1]");
}
public static void fun2()//定义方法2
{
a.Value = 10;
b.Value = 20;
Console.WriteLine($"a={a} [来自 fun2]");
Console.WriteLine($"b={b} [来自 fun2]");
}
public static void Run()
{
var thread1 = new Thread(fun1);
var thread2 = new Thread(fun2);
thread1.Start();//开始线程1
thread2.Start();//开始线程2
}
运行结果跟以上一样,互相不干扰。
在asp.net core 内置DI请求上下文对象底层就用这个。大家感兴趣可以去看看源码。