赞
踩
环境:
说明:
要达到的效果是,每一个线程都有一个单独的容器用来存储数据。实现的方法有三种:线程内的数据槽、ThreadStatic特性、ThreadLocal<T>对象
线程中的数据槽(LocalDataStoreSlot
)是一种给线程存储数据的容器,一个槽只能存一个数据,一个线程可以有很多个槽。可以给槽命名,已命名的槽和线程建立了关联,你可以在任何地方从线程中获取命名的数据槽(GetNamedDataSlot("name-slot")
)。注意:数据存储在槽内的,所以线程存取数据都是要指定具体槽的SetData(slot, "xiaoming")
,GetData(slot)
。还有,槽是对所有线程都有效的,只不过不同的线程的同一个槽内存取的是不同的数据。
线程中的数据槽有两种,未命名的和已命名的:
下面看看数据槽的使用示例:
namespace ConsoleApp1 { class Program { static void Main(string[] args) { //Test1(); //Test2(); //Test3(); Console.WriteLine("ok"); Console.ReadLine(); } /// <summary> /// 测试命名线程槽的GetNamedDataSlot方法 /// </summary> private static void Test3() { LocalDataStoreSlot slot = Thread.GetNamedDataSlot("names-slot"); var thread = new Thread(() => { var slot2 = Thread.GetNamedDataSlot("names-slot"); Console.WriteLine("slot==slot2=>" + (slot == slot2).ToString()); }); thread.Start(); Thread.FreeNamedDataSlot("names-slot"); var slot3 = Thread.AllocateNamedDataSlot("names-slot"); var slot4 = Thread.AllocateNamedDataSlot("names-slot"); Console.WriteLine("slot3==slot4 -> " + (slot3 == slot4)); } /// <summary> /// 测试命名的线程槽 /// </summary> private static void Test2() { LocalDataStoreSlot slot = Thread.AllocateNamedDataSlot("names-slot"); var thread = new Thread(() => { Thread.SetData(slot, "xiaoming"); var data = Thread.GetData(slot); Console.WriteLine("work-thread-slot:" + data); Thread.FreeNamedDataSlot("names-slot"); data = Thread.GetData(slot); var slot2 = Thread.GetNamedDataSlot("names-slot"); data = Thread.GetData(slot2); Console.WriteLine("slot==slot2" + (slot == slot2).ToString()); Console.WriteLine("work-thread-slot:" + data); Thread.SetData(slot, "xiaohong"); Console.WriteLine("work-thread-slot:" + Thread.GetData(slot)); }); thread.Start(); Thread.Sleep(3000); var data2 = Thread.GetData(slot); Console.WriteLine("main-thread-slot:" + data2); } /// <summary> /// 测试未命名的线程槽 /// </summary> private static void Test1() { LocalDataStoreSlot slot = Thread.AllocateDataSlot(); Thread.SetData(slot, "xiaoming"); var data = Thread.GetData(slot); var thread = new Thread(() => { var data2 = Thread.GetData(slot); Console.WriteLine("work-thread-slot:" + data2); }); thread.Start(); Console.WriteLine("main-thread-slot:" + data); } } }
这种方法是在静态字段上添加[ThreadStatic]特性,然后每个线程访问时都是不同的值。
注意:这要求字段必须是静态的,如果不是静态的那么加上[ThreadStatic]特性也没用,因为字段不是特性的话,它就属于一个实例对象,没办法在一个实例对象内根据线程进行隔离。
如果这个字段是静态的,那么这个字段是属于类的,它对所有的线程都一样,此时再给它加上[ThreadStatic]特性就会把这个静态字段进行线程隔离。
下面来看实验代码:
[ThreadStatic]
private static string name = string.Empty;
static void Main(string[] args)
{
var thread = new Thread(() =>
{
name = "xiaoming";
Console.WriteLine("work name=" + name);
});
thread.Start();
thread.Join();
Console.WriteLine("main name=" + name);
Console.WriteLine("ok");
Console.ReadLine();
}
这是一个容器,提供了一个对象专门用来存储和线程相关的对象,它和[ThreadStatic]最大的不同是:不再要求字段是静态的。
具体使用方式如下:
class Program { private ThreadLocal<string> username = new ThreadLocal<string>(); static void Main(string[] args) { var pro = new Program(); var thread = new Thread(() => { pro.username.Value = "xiaoming"; Console.WriteLine("worker username=" + pro.username.Value); }); thread.Start(); thread.Join(); Console.WriteLine("worker username=" + pro.username.Value); Console.WriteLine("ok"); Console.ReadLine(); } }
using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp1 { class Program { #region 测试ThreadStatic、ThreadLocal本地存储 /* * 测试ThreadStatic、ThreadLocal本地存储 */ //[ThreadStatic] //private static string name = string.Empty; //static void Main(string[] args) //{ // ThreadLocal<string> userName = new ThreadLocal<string>(); // var thread = new Thread(() => // { // userName.Value = "xiaohua"; // name = "xiaoming"; // Console.WriteLine("work name=" + name); // Console.WriteLine("work userName=" + userName.Value); // }); // thread.Start(); // thread.Join(); // Console.WriteLine("main name=" + name); // Console.WriteLine("main userName=" + userName.Value); // Console.WriteLine("ok"); // Console.ReadLine(); //} #endregion #region Debug和Releas模式的运行速度对比 //public static void Main(string[] args) //{ // //for (int i = 0; i < 10000; i++) // //{ // // int res = new Random().Next(1, 100000); // // File.AppendAllText("c:\\temp\\ints.txt", res + "\r\n"); // //} // //Release和Debug模式的区别 // var datas = File.ReadAllLines("c:\\temp\\ints.txt").Select(i => int.Parse(i)).ToList<int>(); // for (int i = 0; i < 5; i++) // { // var arr = new int[datas.Count]; // datas.CopyTo(arr); // Stopwatch watch = new Stopwatch(); // watch.Start(); // Order(arr); // watch.Stop(); // Console.WriteLine(watch.Elapsed); // } // Console.WriteLine("ok"); // Console.Read(); //} //public static int[] Order(int[] datas) //{ // for (int i = 0; i < datas.Length; i++) // { // for (int j = i + 1; j < datas.Length; j++) // { // if (datas[i] < datas[j]) // { // int t = datas[i]; // datas[i] = datas[j]; // datas[j] = t; // } // } // } // return datas; //} #endregion public static void Main(string[] args) { var isStop = 0; var t = new Thread(() => { var isSuccess = true; while (isStop == 0) { //Thread.VolatileRead(ref isStop); isSuccess = !isSuccess; } }); t.Start(); Thread.Sleep(1000); isStop = 1; t.Join(); Console.WriteLine("ok"); Console.ReadLine(); //bool isStop = false; //var thread = new Thread(() => // { // var isSuccess = false; // while (!isStop) // { // //这个方法可以指示从内存中读写 // //Thread.MemoryBarrier(); // isSuccess = !isSuccess; // } // }); //thread.Start(); //Thread.Sleep(1000); //isStop = true; //thread.Join(); //Console.WriteLine("ok"); //Console.ReadLine(); //下面不会出现bug //bool isStop = false; //var thread = new Thread(() => //{ // while (true) // { // if (isStop) break; // } //}); //thread.Start(); //Thread.Sleep(1000); //isStop = true; //thread.Join(); //Console.WriteLine("ok"); //Console.ReadLine(); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。