多线程和并发管理 .NET多线程服务
线程相关静态变量
默认静态变量应用程序域所有线程可见。如果静态变量需要在线程间共享,同步访问也就必然了。
线程相关静态变量保证线程安全,同一时间只有一个线程可访问,且每个线程都有该静态变量的拷贝。
- public class MyClass
- {
- //.NET支持线程相关静态变量
- //该特性只可修饰类的静态成员变量,不能用于属性,方法
- [ThreadStatic]
- private static m_MyString;
- public static string MyString
- {
- set { m_MyString = value; }
- get { return m_MyString; }
- }
- }
public class MyClass { //.NET支持线程相关静态变量 //该特性只可修饰类的静态成员变量,不能用于属性,方法 [ThreadStatic] private static m_MyString; public static string MyString { set { m_MyString = value; } get { return m_MyString; } } }
线程本地存储(TLS)
全局托管堆上分配的对象对于所有应用程序域的所有线程都可见可访问(因此需要同步访问机制)。
.NET提供了线程专用堆TLS,无需同步那些分配到TLS上的对象访问,因为只有一个线程可以访问他们。
TLS提供了槽(LocalDataStoreSlot对象),用来存储对象。分为:命名槽(一定要显示释放),未命名槽(垃圾回收器自动释放)。
命名槽:
- Thread.CurrentThread.Name = "66";
- int number = 8;
- //显示释放命名槽
- Thread.FreeNamedDataSlot("My_TLS_Slot");
- //在当前线程上分配一命名槽
- LocalDataStoreSlot dataSlot = Thread.AllocateNamedDataSlot("My_TLS_Slot");
- //在当前线程上将数据存入命名槽(只有当前线程中的成员才可以访问)
- Thread.SetData(dataSlot, 8);
- //新建另一线程
- Thread thread = new Thread(GetData_2);
- thread.Name = "lulu";
- thread.Start();
- GetData();
- private void GetData()
- {
- object obj;
- //获取当前线程命名槽
- LocalDataStoreSlot dataSlot = Thread.GetNamedDataSlot("My_TLS_Slot");
- //获取当前线程槽中存储的值
- obj = Thread.GetData(dataSlot);
- int number = (int)obj;
- //输出:66 , 8
- //说明槽中数据只由创建槽的线程访问(只有一个线程可访问)
- Response.Write(Thread.CurrentThread.Name + " , " + number);
- }
- private void GetData_2()
- {
- object obj;
- LocalDataStoreSlot dataSlot = Thread.GetNamedDataSlot("My_TLS_Slot");
- obj = Thread.GetData(dataSlot);
- //输出:lulu
- //说明访问不到槽中数据,因为当前方法由另一线程调用
- if (obj == null)
- {
- Response.Write(Thread.CurrentThread.Name);
- }
- }
Thread.CurrentThread.Name = "66"; int number = 8; //显示释放命名槽 Thread.FreeNamedDataSlot("My_TLS_Slot"); //在当前线程上分配一命名槽 LocalDataStoreSlot dataSlot = Thread.AllocateNamedDataSlot("My_TLS_Slot"); //在当前线程上将数据存入命名槽(只有当前线程中的成员才可以访问) Thread.SetData(dataSlot, 8); //新建另一线程 Thread thread = new Thread(GetData_2); thread.Name = "lulu"; thread.Start(); GetData(); private void GetData() { object obj; //获取当前线程命名槽 LocalDataStoreSlot dataSlot = Thread.GetNamedDataSlot("My_TLS_Slot"); //获取当前线程槽中存储的值 obj = Thread.GetData(dataSlot); int number = (int)obj; //输出:66 , 8 //说明槽中数据只由创建槽的线程访问(只有一个线程可访问) Response.Write(Thread.CurrentThread.Name + " , " + number); } private void GetData_2() { object obj; LocalDataStoreSlot dataSlot = Thread.GetNamedDataSlot("My_TLS_Slot"); obj = Thread.GetData(dataSlot); //输出:lulu //说明访问不到槽中数据,因为当前方法由另一线程调用 if (obj == null) { Response.Write(Thread.CurrentThread.Name); } }
未命名槽:
- //共享该对象
- private LocalDataStoreSlot dataSlot;
- protected void Page_Load(object sender, EventArgs e)
- {
- Thread.CurrentThread.Name = "66";
- //在当前线程上分配一未命名槽(由垃圾回收器释放,无需显示释放)
- dataSlot = Thread.AllocateDataSlot();
- //在当前线程上将数据存入未命名槽(只有当前线程中的成员才可以访问)
- Thread.SetData(dataSlot, 8);
- //创建一新线程
- Thread thread = new Thread(GetData_2);
- thread.Name = "lulu";
- thread.Start();
- GetData();
- }
- private void GetData()
- {
- //获取当前线程未命名槽中值
- object obj = Thread.GetData(dataSlot);
- Response.Write(Thread.CurrentThread.Name + " , " + (int)obj);
- }
- private void GetData_2()
- {
- object obj = Thread.GetData(dataSlot);
- if (obj == null)
- {
- Response.Write(Thread.CurrentThread.Name);
- }
- }
//共享该对象 private LocalDataStoreSlot dataSlot; protected void Page_Load(object sender, EventArgs e) { Thread.CurrentThread.Name = "66"; //在当前线程上分配一未命名槽(由垃圾回收器释放,无需显示释放) dataSlot = Thread.AllocateDataSlot(); //在当前线程上将数据存入未命名槽(只有当前线程中的成员才可以访问) Thread.SetData(dataSlot, 8); //创建一新线程 Thread thread = new Thread(GetData_2); thread.Name = "lulu"; thread.Start(); GetData(); } private void GetData() { //获取当前线程未命名槽中值 object obj = Thread.GetData(dataSlot); Response.Write(Thread.CurrentThread.Name + " , " + (int)obj); } private void GetData_2() { object obj = Thread.GetData(dataSlot); if (obj == null) { Response.Write(Thread.CurrentThread.Name); } }
线程池
由.NET管理,包含一组线程随时准备为应用程序的请求服务(异步调用,远程调用,计时器调用都用到线程池)。可通过ThreadPool静态类访问。
线程池中实际有2种线程:工作线程,完成端口线程。
默认情况下,线程池工作线程最大数是每个CPU每个进程25个。