談談ThreadStatic屬性用法
如果一個型別包含非靜態欄位(例項欄位),則對於該欄位,該型別的每個例項均有其自身的獨立儲存位置;在一個例項中設定欄位並不影響其他例項中該欄位的值。而相反,對於靜態欄位,無論有多少例項,該欄位只位於一個儲存位置(或者,更具體地說,在每個 AppDomain
中,只位於一個儲存位置)。然而,如果將 System.ThreadStaticAttribute
應用於靜態欄位,則該欄位將變為執行緒靜態欄位,即,對於該欄位,每個執行緒(而非例項)將保留其自身的儲存位置。在一個執行緒上設定執行緒靜態的值將不會影響其在其他執行緒上的值。
可能經常做多執行緒、執行緒池的童鞋早就知道這種問題,原諒我一直對執行緒研究不深。
這個東西好像出現有一段時間了,不過最近我才用到,做的API
的服務,用來儲存當前請求的上下文內容,原來用過Thread.SetData
,不過原來的使用者量沒這麼大,沒發現問題。
查了一些關於ThreadStatic
的說明,有一些人說好,也有人說坑的,的確有坑,下面看個例子:
class Program
{
[ThreadStatic]
private static int? NowI;
//private static string resultString = "";
static void Main(string[] args)
{
//resultString = "";
for (var i = 0; i < 100; i++)
{
int i1 = i;
var t = new Task(() =>
{
if(NowI == null) NowI = i1;
//var nowI = Thread.GetData(Thread.GetNamedDataSlot("NowI"));
//if (nowI == null)
//{
// nowI = i1;
// Thread.SetData(Thread.GetNamedDataSlot("NowI"), i1);
//}
Console.WriteLine(string.Format("第{0}次迴圈, i值:{1},執行緒ID:{2}\r\n", i1, NowI, Thread.CurrentThread.ManagedThreadId));
});
t.Start();
}
//Console.WriteLine(resultString.ToString());
Console.Read();
}
}
NowI
儲存在ThreadStatic
中,迴圈100次,開100個執行緒,執行結果(結果沒排序,不過已經可以看出問題了):
第1次迴圈, i值:1,執行緒ID:12
第2次迴圈, i值:1,執行緒ID:12
第3次迴圈, i值:3,執行緒ID:15
第0次迴圈, i值:0,執行緒ID:6
第5次迴圈, i值:5,執行緒ID:17
第4次迴圈, i值:4,執行緒ID:14
第6次迴圈, i值:6,執行緒ID:11
第12次迴圈, i值:6,執行緒ID:11
第13次迴圈, i值:6,執行緒ID:11
第14次迴圈, i值:6,執行緒ID:11
第15次迴圈, i值:6,執行緒ID:11
第16次迴圈, i值:6,執行緒ID:11
第17次迴圈, i值:6,執行緒ID:11
第18次迴圈, i值:6,執行緒ID:11
第19次迴圈, i值:6,執行緒ID:11
第20次迴圈, i值:6,執行緒ID:11
第21次迴圈, i值:6,執行緒ID:11
第22次迴圈, i值:6,執行緒ID:11
第23次迴圈, i值:6,執行緒ID:11
第24次迴圈, i值:6,執行緒ID:11
......
可以看出, 執行緒ID
一樣的,儲存的NowI
變數的值是一樣的,再猜,可能是GC
沒有回收垃圾,然後在new Task
最後加上GC.Collect
,然而並沒有什卵用。
問題原因是這樣的:當執行緒重用時,垃圾回收並沒有回收上次的空間,其中變數值依然存在,如果不重新賦值,必然出現延用上次值的現象。
所以,解決辦法就是線上程結束前把ThreadStatic
變數清空。
再看結果:
第0次迴圈, i值:0,執行緒ID:10
第3次迴圈, i值:3,執行緒ID:12
第4次迴圈, i值:4,執行緒ID:10
第1次迴圈, i值:1,執行緒ID:11
第5次迴圈, i值:5,執行緒ID:12
第6次迴圈, i值:6,執行緒ID:10
第9次迴圈, i值:9,執行緒ID:10
第8次迴圈, i值:8,執行緒ID:12
第13次迴圈, i值:13,執行緒ID:12
......
這次就正常了。
不過,有沒有辦法可以統一對執行緒結束後進行處理呢,把所有這種變更重置一下,目前還沒找到,希望大神們弄過的給個意見。
相關文章
- 淺談質量屬性
- 淺談 Swift 中的屬性(PropertySwift
- 淺談 Swift 中的屬性(Property)Swift
- 淺談WPF之屬性系統
- 談談Oracle interMedia的用法Oracle
- 三談屬性動畫——Keyframe以及ViewPropertyAnimator動畫View
- 淺談Flex佈局的屬性及使用Flex
- 這篇文章,我們來談一談Spring中的屬性注入Spring
- 淺談promise用法Promise
- 老生常談category增加屬性的幾種操作Go
- LogMiner 用法淺談
- 淺談DataSet 的用法
- CSS zoom屬性用法CSSOOM
- HTML5 雜談 Video 元素的poster屬性HTMLIDE
- 談談服務端快取的幾種用法服務端快取
- React屬性用法總結React
- javascript textContent屬性用法JavaScript
- background屬性用法詳解
- UITableView 屬性用法詳解UIView
- 談談資料一致性
- 談談機器學習模型的可解釋性機器學習模型
- 淺談CSS3中display屬性的Flex佈局CSSS3Flex
- 談談資料戰略的重要性
- Android屬性動畫詳解(一),屬性動畫基本用法Android動畫
- 淺談Invoke 和 BegionInvoke的用法
- 也談TTreeView、TListView用法一二 (轉)View
- 淺談CSS3中display屬性的Flex佈局(轉)CSSS3Flex
- css transition屬性用法介紹CSS
- javascript callee和caller屬性用法JavaScript
- pageYOffset與pageXOffset屬性用法
- css border-color屬性用法CSS
- list-style-image屬性用法
- easyui tree自定義屬性用法UI
- 談談資料傳輸中的安全性
- js的屬性物件的specified屬性用法簡單介紹JS物件
- 淺談Golang中select的用法Golang
- 淺談python中的xpath用法Python
- js的returnValue屬性用法介紹JS