談談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
......
這次就正常了。
不過,有沒有辦法可以統一對執行緒結束後進行處理呢,把所有這種變更重置一下,目前還沒找到,希望大神們弄過的給個意見。
相關文章
- 淺談質量屬性
- 淺談WPF之屬性系統
- 淺談 Swift 中的屬性(PropertySwift
- 三談屬性動畫——Keyframe以及ViewPropertyAnimator動畫View
- 這篇文章,我們來談一談Spring中的屬性注入Spring
- 淺談promise用法Promise
- 淺談Flex佈局的屬性及使用Flex
- React屬性用法總結React
- 淺談CSS3中display屬性的Flex佈局CSSS3Flex
- 談談資料一致性
- 淺談Golang中select的用法Golang
- 淺談python中的xpath用法Python
- 淺談Invoke 和 BegionInvoke的用法
- 談談資料戰略的重要性
- 淺談CSS3中display屬性的Flex佈局(轉)CSSS3Flex
- 談談資料傳輸中的安全性
- 淺談vue中provide和inject 用法VueIDE
- 再談屬性動畫——介紹以及自定義Interpolator插值器動畫
- html中Position屬性值介紹和position屬性四種用法HTML
- 談談Bug引起的複雜性“Bug-O” — OverreactedReact
- 談談機器學習模型的可解釋性機器學習模型
- 談一談屬於你的前端生涯規劃與前端技術前端
- PHP安全性漫談PHP
- 淺談對屬性描述符__get__、__set__、__delete__的理解delete
- 老生常談:Promise 用法與原始碼分析Promise原始碼
- 真正的競爭性談判,到底應該怎樣談?
- 談談近況,談談自由職業,談談“金飯碗”
- (八)Mybatis當中#{}常用屬性的用法MyBatis
- vue.js計算屬性用法(computed)Vue.js
- 淺談Redis的隱性成本Redis
- 寵物趣味性小談
- 淺談Vue-router的部分高階用法Vue
- 內嵌標籤frameset框架屬性及用法框架
- 談談PromisePromise
- 談談RaftRaft
- 羽夏閒談—— C 的 scanf 的高階用法
- 談服務可用性監控
- 談談 Web 安全Web