using System; using System.Collections.Generic; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MultiThreadingStudy.Core { /// /// 线程本地存储 执行器 /// public class ThreadLocalStorage { /// /// 不使用线程本地存储 /// public static void Run() { var demo = new Computer(); var thread_a = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_a" }; var thread_b = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_b" }; thread_a.Start(); thread_b.Start(); thread_a.Join(); thread_b.Join(); //调用线程:[主线程|内核线程] 共享字段的值。不加处理的话,可能小于多线程调用次数之和。 Console.WriteLine("调用线程的共享变量值 = " + Computer.TotalCount); } /// /// 使用 ThreadStatic 特性 /// public static void UseThreadStaticAttribute() { var demo = new ThreadStaticComputer(); var thread_a = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_a" }; var thread_b = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_b" }; thread_a.Start(); thread_b.Start(); thread_a.Join(); thread_b.Join(); //调用线程:[主线程|内核线程] 共享字段的值。不加处理的话,可能小于多线程调用次数之和。 Console.WriteLine("调用线程的共享变量值 = " + Computer.TotalCount); } /// /// 使用数据槽 /// public static void UseDataSlot() { var demo = new DataSlotComputer(); var thread_a = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_a" }; var thread_b = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_b" }; thread_a.Start(); thread_b.Start(); thread_a.Join(); thread_b.Join(); //调用线程:[主线程|内核线程] 共享字段的值。不加处理的话,可能小于多线程调用次数之和。 Console.WriteLine("调用线程的共享变量值 = " + Computer.TotalCount); } /// /// 使用 ThreadLocal 泛型类 /// public static void UseThreadLocalClass() { var demo = new ThreadLocalComputer(); var thread_a = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_a" }; var thread_b = new Thread(new ThreadStart(demo.SumCount)) { Name = "thread_b" }; thread_a.Start(); thread_b.Start(); thread_a.Join(); thread_b.Join(); //调用线程:[主线程|内核线程] 共享字段的值。不加处理的话,可能小于多线程调用次数之和。 Console.WriteLine("调用线程的共享变量值 = " + Computer.TotalCount); } /// /// 使用 AsyncLocal 泛型类 /// public static void UseAsyncLocalClass() { var demo = new AsyncLocalComputer(); var thread_a = new Thread(async () => { await demo.SumCountAsync(); }) { Name = "thread_a" }; var thread_b = new Thread(async () => { await demo.SumCountAsync(); }) { Name = "thread_b" }; thread_a.Start(); thread_b.Start(); thread_a.Join(); thread_b.Join(); //调用线程:[主线程|内核线程] 共享字段的值。不加处理的话,可能小于多线程调用次数之和。 Console.WriteLine("调用线程的共享变量值 = " + Computer.TotalCount); } } /// /// 不使用本地存储 /// /// /// 由于 ++ -- += -= 等对共享变量的操作不是原子性的,多线程下是不安全的。 /// public class Computer { /// /// 总计算次数 /// //[ThreadStatic] public static int TotalCount = 0; /// /// 循环次数 /// public readonly int LoopNumber = 1000; /// /// 累加计数 /// public void SumCount() { for (int i = 1; i <= LoopNumber; i++) { //因为 += 是和等于的两步操作,所以不是线程安全的。 TotalCount += 1; //如果使用原子操作,则是线程安全的 //Interlocked.Increment(ref TotalCount); //加休眠是为了让并发效果明显,不加休眠可以增加循环次数 Thread.Sleep(1); } Console.WriteLine($"线程[{Thread.CurrentThread.ManagedThreadId.ToString("000")}]执行后,共享变量 {nameof(TotalCount)} = {TotalCount}"); } } /// /// 使用本地存储:ThreadStatic 特性 /// /// /// 特点:只能用于静态变量上,不能用于实例上(语法不报错,实际不起作用) /// public class ThreadStaticComputer { /// /// 总计算次数 /// [ThreadStatic] public static int TotalCount = 0; /// /// 循环次数 /// public readonly int LoopNumber = 100; /// /// 累加计数 /// public void SumCount() { for (int i = 1; i <= LoopNumber; i++) { TotalCount += 1; Thread.Sleep(0); } Console.WriteLine($"线程[{Thread.CurrentThread.ManagedThreadId.ToString("000")}]执行后,共享变量 {nameof(TotalCount)} = {TotalCount}"); } } /// /// 使用本地存储:数据槽 /// /// /// 特点:可以用于静态也可用于实例 /// public class DataSlotComputer { /// /// 总计算次数 /// public static int TotalCount = 0; /// /// 循环次数 /// public readonly int LoopNumber = 100; /// /// 数据槽 /// public LocalDataStoreSlot storeSlot = Thread.AllocateDataSlot(); /// /// 累加计数值 /// public void SumCount() { for (int i = 1; i <= LoopNumber; i++) { Thread.SetData(storeSlot, i); //加休眠是为了让并发效果明显,不加休眠可以增加循环次数 Thread.Sleep(0); } //严格讲,这里也不是线程安全的。少量线程不安全的概率很小.可以使用原子操作实现。 TotalCount += (int)Thread.GetData(storeSlot); //保证线程安全的话,可用原子操作 //Interlocked.Add(ref TotalCount, (int)Thread.GetData(storeSlot)); Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId.ToString("000")}执行后,共享变量{nameof(TotalCount)} = {TotalCount}"); } } /// /// 使用本地存储:ThreadLocal泛型类 /// /// /// 特点:1、对静态和实例字段都提供了线程本地存储支持,并允许指定默认值 /// 2、ThreadLocal的值是延迟计算的:每线程第一次调用时计算实际的值 /// public class ThreadLocalComputer { /// /// 总计算次数 /// public static int TotalCount = 0; /// /// 循环次数 /// public readonly int LoopNumber = 100; /// /// 线程本地存储数据 /// public static ThreadLocal threadTotalCount = new ThreadLocal(); /// /// 累加计数值 /// public void SumCount() { for (int i = 1; i <= LoopNumber; i++) { threadTotalCount.Value += 1; //加休眠是为了让并发效果明显,不加休眠可以增加循环次数 Thread.Sleep(0); } TotalCount += threadTotalCount.Value; //保证线程安全的话,可用原子操作 //Interlocked.Add(ref TotalCount, threadTotalCount.Value); Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId.ToString("000")}执行后,共享变量{nameof(TotalCount)} = {TotalCount}"); } } /// /// 使用本地存储:AsyncLocal泛型类 /// /// /// 特点:针对 TPL 异步方法 /// public class AsyncLocalComputer { /// /// 总计算次数 /// public static int TotalCount = 0; /// /// 循环次数 /// public readonly int LoopNumber = 100; /// /// 线程本地存储数据 /// public static AsyncLocal threadTotalCount = new AsyncLocal(); /// /// 累加计数值 /// public Task SumCountAsync() { for (int i = 1; i <= LoopNumber; i++) { threadTotalCount.Value += 1; //加休眠是为了让并发效果明显,不加休眠可以增加循环次数 Thread.Sleep(0); } Interlocked.Add(ref TotalCount, threadTotalCount.Value); Console.WriteLine($"线程{Thread.CurrentThread.ManagedThreadId.ToString("000")}执行后,共享变量{nameof(TotalCount)} = {TotalCount}"); return Task.CompletedTask; } } }