生活随笔
收集整理的這篇文章主要介紹了
多线程中Local Store Slot(本地存储槽)[转]
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
1. 使用ThreadStatic特性
ThreadStatic特性是最簡單的TLS使用,且只支持靜態(tài)字段,只需要在字段上標(biāo)記這個特性就可以了:
[ThreadStatic]?? static string str = "hehe";?? static void Main()?? {?? //另一個線程只會修改自己TLS中的str變量 ??? Thread th = new Thread(() => { str = "Mgen"; Display(); });?? ??? th.Start();?? ??? th.Join();?? ??? Display();?? }?? static void Display()?? {?? ??? Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, str);?? }? 運行結(jié)果:
1 hehe
3 Mgen
可以看到,str靜態(tài)字段在兩個線程中都是獨立存儲的,互相不會被修改。
2. 使用命名的LocalDataStoreSlot類型
顯然ThreadStatic特性只支持靜態(tài)字段太受限制了。.NET線程類型中的LocalDataStoreSlot提供更好的TLS支持。我們先來看看命名的LocalDataStoreSlot類型,可以通過Thread.AllocateNamedDataSlot來分配一個命名的空間,通過Thread.FreeNamedDataSlot來銷毀一個命名的空間。空間數(shù)據(jù)的獲取和設(shè)置則通過Thread類型的GetData方法和SetData方法。
static void Main()?? {?? //創(chuàng)建Slot ??? LocalDataStoreSlot slot = Thread.AllocateNamedDataSlot("slot");?? //設(shè)置TLS中的值 ??? Thread.SetData(slot, "hehe");?? //修改TLS的線程 ??? Thread th = new Thread(() =>?? ??????? {?? ??????????? Thread.SetData(slot, "Mgen");?? ??????????? Display();?? ??????? });?? ??? th.Start();?? ??? th.Join();?? ??? Display();?? //清除Slot ??? Thread.FreeNamedDataSlot("slot");?? }?? //顯示TLS中Slot值 static void Display()?? {?? ??? LocalDataStoreSlot dataslot = Thread.GetNamedDataSlot("slot");?? ??? Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, Thread.GetData(dataslot));?? }? 輸出:
3 Mgen
1 hehe
3. 使用未命名的LocalDataStoreSlot類型
線程同樣支持未命名的LocalDataStoreSlot,未命名的LocalDataStoreSlot不需要手動清除,分配則需要Thread.AllocateDataSlot方法。注意由于未命名的LocalDataStoreSlot沒有名稱,因此無法使用Thread.GetNamedDataSlot方法,只能在多個線程中引用同一個LocalDataStoreSlot才可以對TLS空間進行操作,將上面的命名的LocalDataStoreSlot代碼改成未命名的LocalDataStoreSlot執(zhí)行:
//靜態(tài)LocalDataStoreSlot變量 static LocalDataStoreSlot slot;?? static void Main()?? {?? //創(chuàng)建Slot ??? slot = Thread.AllocateDataSlot();?? //設(shè)置TLS中的值 ??? Thread.SetData(slot, "hehe");?? //修改TLS的線程 ??? Thread th = new Thread(() =>?? ??????? {?? ??????????? Thread.SetData(slot, "Mgen");?? ??????????? Display();?? ??????? });?? ??? th.Start();?? ??? th.Join();?? ??? Display();?? }?? //顯示TLS中Slot值 static void Display()?? {?? ??? Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, Thread.GetData(slot));?? }?? 4. 使用.NET 4.0的ThreadLocal<T>類型
.NET 4.0在線程方面加入了很多東西,其中就包括ThreadLocal<T>類型,他的出現(xiàn)更大的簡化了TLS的操作。ThreadLocal<T>類型和Lazy<T>驚人相似,構(gòu)造函數(shù)參數(shù)是Func<T>用來創(chuàng)建對象(當(dāng)然也可以理解成對象的默認(rèn)值),然后用Value屬性來得到或者設(shè)置這個對象。ThreadLocal的操作或多或少有點像上面的未命名的LocalDataStoreSlot,但ThreadLocal感覺更簡潔更好理解。
static ThreadLocal<string> local;?? static void Main()?? {?? //創(chuàng)建ThreadLocal并提供默認(rèn)值 ??? local = new ThreadLocal<string>(() => "hehe");?? //修改TLS的線程 ??? Thread th = new Thread(() =>?? ??????? {?? ??????????? local.Value = "Mgen";?? ??????????? Display();?? ??????? });?? ??? th.Start();?? ??? th.Join();?? ??? Display();?? }?? //顯示TLS中數(shù)據(jù)值 static void Display()?? {?? ??? Console.WriteLine("{0} {1}", Thread.CurrentThread.ManagedThreadId, local.Value);?? }? 輸出:
3 Mgen
1 hehe?
5. 強調(diào)一下不同方法和TLS的默認(rèn)值
上面代碼都是一個一個線程設(shè)置值,另一個線程直接修改值然后輸出,不會覺察到TLS中默認(rèn)值的狀況,下面專門強調(diào)一下不同方法的默認(rèn)值狀況。ThreadStatic不提供默認(rèn)值:
[ThreadStatic]?? static int i = 123;?? static void Main()?? {?? //輸出本地線程TLS數(shù)據(jù)值 ??? Console.WriteLine(i);?? //輸出另一個線程TLS數(shù)據(jù)值 ??? ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(i));?? //控制臺等待線程結(jié)束 ??? Console.ReadKey();?? }? 輸出:
123
0
顯然本地線程TLS數(shù)據(jù)時123,而靜態(tài)變量的默認(rèn)值不會在另一個線程中初始化的。
LocalDataStoreSlot很容易可以看出來,不可能有默認(rèn)值,因為初始化只能構(gòu)造一個空間,而不能賦予它值,Thread.SetData顯然只會在TLS中設(shè)置數(shù)據(jù),還是用代碼演示一下:
static LocalDataStoreSlot slot = Thread.AllocateDataSlot();?? static void Main()?? {?? ??? Thread.SetData(slot, 123);?? //輸出本地線程TLS數(shù)據(jù)值 ??? Console.WriteLine(Thread.GetData(slot));?? //輸出另一個線程TLS數(shù)據(jù)值 ??? ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(Thread.GetData(slot) == null));?? //控制臺等待線程結(jié)束 ??? Console.ReadKey();?? }? 輸出:
123
True
第二行是True,那么另一個線程中的數(shù)據(jù)是null。
最后重點:.NET 4.0后的ThreadLocal會提供默認(rèn)值的,還記得我上面說的那句話“ThreadLocal的操作或多或少有點像上面的未命名的LocalDataStoreSlot”?有人可能會問那為什么要創(chuàng)造出ThreadLocal?還有一個很大的區(qū)別ThreadLocal可以提供TLS中數(shù)據(jù)的默認(rèn)值。(另外還有ThreadLocal是泛型類,而LocalDataStoreSlot不是)。
static ThreadLocal<int> local = new ThreadLocal<int>(() => 123);?? static void Main()?? {?? //輸出本地線程TLS數(shù)據(jù)值 ??? Console.WriteLine(local.Value);?? //輸出另一個線程TLS數(shù)據(jù)值 ??? ThreadPool.QueueUserWorkItem(_ => Console.WriteLine(local.Value));?? //控制臺等待線程結(jié)束 ??? Console.ReadKey();?? }? 輸出:
123
123
?
這篇文章也可以參考
http://www.cnblogs.com/lulu/archive/2012/03/17/2403872.html
轉(zhuǎn)載于:https://www.cnblogs.com/chenqingwei/p/5003688.html
總結(jié)
以上是生活随笔為你收集整理的多线程中Local Store Slot(本地存储槽)[转]的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。