c# 变量,对象,静态类型,集合类的线程安全回顾
?? 1.變量的線程安全性與變量的作用域有關(guān)。
???2.對(duì)象?
? ? ?對(duì)象是類型的實(shí)例
? ? ?在創(chuàng)建對(duì)象時(shí),會(huì)單獨(dú)有內(nèi)存區(qū)域存儲(chǔ)對(duì)象的屬性和方法。所以,一個(gè)類型的多個(gè)實(shí)例,在執(zhí)行時(shí),只要沒(méi)有靜態(tài)變量的參與,應(yīng)該都是線程安全的。
這跟我們調(diào)試狀態(tài)下,是不一樣的。調(diào)試狀態(tài)下,如果多個(gè)線程都創(chuàng)建某實(shí)例的對(duì)象,每個(gè)對(duì)象都調(diào)用自身方法,在調(diào)試是,會(huì)發(fā)現(xiàn)是訪問(wèn)的同一個(gè)代碼,多個(gè)線程是有沖突的。但是,真正的運(yùn)行環(huán)境是線程安全的。
? ? ? 以銷售員為例,假設(shè)產(chǎn)品是充足的,多個(gè)銷售員,銷售產(chǎn)品,調(diào)用方法:Sale(),其是線程安全的。
? ? ? 但是,如果涉及到倉(cāng)庫(kù),必須倉(cāng)庫(kù)有足夠的產(chǎn)品才能進(jìn)行銷售,這時(shí),多個(gè)銷售人員就有了臨界資源:倉(cāng)庫(kù)。
? ? ? 在這里我們只討論對(duì)象的普通方法。至于方法傳入的參數(shù),以及方法內(nèi)對(duì)靜態(tài)變量操作的,這里需要根據(jù)參數(shù)和靜態(tài)變量來(lái)判定方法的線程安全性。
? ? ? 銷售員案例:
using System; using System.Threading;namespace MutiThreadSample.Sale {/// <summary>/// 銷售/// </summary>public class Saler{/// <summary>/// 名稱/// </summary>public string Name { get; set; }/// <summary>/// 間隔時(shí)間/// </summary>public int IntervalTime { get; set; }/// <summary>/// 單位時(shí)間銷售運(yùn)量/// </summary>public int SaleAmount { get; set; }/// <summary>/// 銷售/// </summary>public void Sale(){Console.WriteLine("銷售:{0} 于 {1} 銷售產(chǎn)品 {2}", this.Name, DateTime.Now.Millisecond, this.SaleAmount);Thread.Sleep(IntervalTime);}/// <summary>/// 銷售/// </summary>/// <param name="interval">時(shí)間間隔</param>public void Sale(object obj){WHouseThreadParameter parameter = obj as WHouseThreadParameter;if (parameter != null){while (parameter.WHouse != null && parameter.WHouse.CanOut(this.SaleAmount)){parameter.WHouse.Outgoing(this.SaleAmount);Console.WriteLine("Thread{0}, 銷售:{1} 于 {2} 銷售出庫(kù)產(chǎn)品 {3}", Thread.CurrentThread.Name, this.Name, DateTime.Now.Millisecond, this.SaleAmount);Thread.Sleep(this.IntervalTime);}}}} }? ? ? 3靜態(tài)類型
? ? ? 已經(jīng)講了類的實(shí)例--對(duì)象的多線程安全性問(wèn)題。這里只討論類型的靜態(tài)變量和靜態(tài)方法。
? ? ? 當(dāng)靜態(tài)類被訪問(wèn)的時(shí)候,CLR會(huì)調(diào)用類的靜態(tài)構(gòu)造器(類型構(gòu)造器),創(chuàng)建靜態(tài)類的類型對(duì)象,CLR希望確保每個(gè)應(yīng)用程序域內(nèi)只執(zhí)行一次類型構(gòu)造器,為了做到這一點(diǎn),在調(diào)用類型構(gòu)造器時(shí),CLR會(huì)為靜態(tài)類加一個(gè)互斥的線程同步鎖,因此,如果多個(gè)線程試圖同時(shí)調(diào)用某個(gè)類型的靜態(tài)構(gòu)造器時(shí),那么只有一個(gè)線程可以獲得對(duì)靜態(tài)類的訪問(wèn)權(quán),其他的線程都被阻塞。第一個(gè)線程執(zhí)行完 類型構(gòu)造器的代碼并釋放構(gòu)造器之后,其他阻塞的線程被喚醒,然后發(fā)現(xiàn)構(gòu)造器被執(zhí)行過(guò),因此,這些線程不再執(zhí)行構(gòu)造器,只是從構(gòu)造器簡(jiǎn)單的返回。如果再一次調(diào)用這些方法,CLR就會(huì)意識(shí)到類型構(gòu)造器被執(zhí)行過(guò),從而不會(huì)在被調(diào)用。
? ? ? 調(diào)用類中的靜態(tài)方法,或者訪問(wèn)類中的靜態(tài)成員變量,過(guò)程同上,所以說(shuō)靜態(tài)類是線程安全的。
? ? ? 最簡(jiǎn)單的例子,就是數(shù)據(jù)庫(kù)操作幫助類。這個(gè)類的方法和屬性是線程安全的。
?
using System;namespace MutiThreadSample.Static {public class SqlHelper{ /// <summary>/// 數(shù)據(jù)庫(kù)連接/// </summary>private static readonly string ConnectionString = "";/// <summary>/// 執(zhí)行數(shù)據(jù)庫(kù)命令/// </summary>/// <param name="sql">SQL語(yǔ)句</param>public static void ExcuteNonQuery(string sql){ //執(zhí)行數(shù)據(jù)操作,比如新增、編輯、刪除}} }?
? ? ? ?但是,對(duì)于靜態(tài)變量其線程安全性是相對(duì)的,如果多個(gè)線程來(lái)修改靜態(tài)變量,這就不一定是線程安全的。而靜態(tài)方法的線程安全性,直接跟傳入的參數(shù)有關(guān)。
? ? ? ?總之:
? ? ? 針對(duì)變量、對(duì)象、類型,說(shuō)線程安全性,比較籠統(tǒng),在這里,主要是想讓大家明白,哪些地方需要注意線程安全性。對(duì)于變量、對(duì)象(屬性、方法)、靜態(tài)變量、靜態(tài)方法,其線程安全性是相對(duì)的,需要根據(jù)實(shí)際情況而定。
? ? ?萬(wàn)劍不離其宗,其判定標(biāo)準(zhǔn):是否有臨界資源。
?4、集合類型是線程安全的嗎?
? ? ? 常用的集合類型有List、Dictionary、HashTable、HashMap等。在編碼中,集合應(yīng)用很廣泛中,常用集合來(lái)自定義Cache,這時(shí)候必須考慮線程同步問(wèn)題。?
? ? ? 默認(rèn)情況下集合不是線程安全的。在System.Collections 命名空間中只有幾個(gè)類提供Synchronize方法,該方法能夠超越集合創(chuàng)建線程安全包裝。但是,System.Collections命名空間中的所有類都提供SyncRoot屬性,可供派生類創(chuàng)建自己的線程安全包裝。還提供了IsSynchronized屬性以確定集合是否是線程安全的。但是ICollection泛型接口中不提供同步功能,非泛型接口支持這個(gè)功能。
? ? ?Dictionary(MSDN解釋)
? ? ?此類型的公共靜態(tài)(在 Visual Basic 中為 Shared)成員是線程安全的。 但不保證所有實(shí)例成員都是線程安全的。
? ? ?只要不修改該集合,Dictionary<TKey, TValue> 就可以同時(shí)支持多個(gè)閱讀器。 即便如此,從頭到尾對(duì)一個(gè)集合進(jìn)行枚舉本質(zhì)上并不是一個(gè)線程安全的過(guò)程。 當(dāng)出現(xiàn)枚舉與寫(xiě)訪問(wèn)互相爭(zhēng)用這種極少發(fā)生的情況時(shí),必須在整個(gè)枚舉過(guò)程中鎖定集合。 若允許多個(gè)線程對(duì)集合執(zhí)行讀寫(xiě)操作,您必須實(shí)現(xiàn)自己的同步。
? ? ? 很多集合類型都和Dictionary類似。默認(rèn)情況下是線程不安全的。當(dāng)然微軟也提供了線程安全的Hashtable.
? ? ? HashTable?
? ? ? Hashtable 是線程安全的,可由多個(gè)讀取器線程和一個(gè)寫(xiě)入線程使用。 多線程使用時(shí),如果只有一個(gè)線程執(zhí)行寫(xiě)入(更新)操作,則它是線程安全的,從而允許進(jìn)行無(wú)鎖定的讀取(若編寫(xiě)器序列化為 Hashtable)。 若要支持多個(gè)編寫(xiě)器,如果沒(méi)有任何線程在讀取 Hashtable 對(duì)象,則對(duì) Hashtable 的所有操作都必須通過(guò) Synchronized 方法返回的包裝完成。
? ? ? 從頭到尾對(duì)一個(gè)集合進(jìn)行枚舉本質(zhì)上并不是一個(gè)線程安全的過(guò)程。 即使某個(gè)集合已同步,其他線程仍可以修改該集合,這會(huì)導(dǎo)致枚舉數(shù)引發(fā)異常。 若要在枚舉過(guò)程中保證線程安全,可以在整個(gè)枚舉過(guò)程中鎖定集合,或者捕捉由于其他線程進(jìn)行的更改而引發(fā)的異常。
? ? ?線程安全起見(jiàn)請(qǐng)使用以下方法聲明
/// <summary>/// Syncronized方法用來(lái)創(chuàng)造一個(gè)新的對(duì)象的線程安全包裝/// </summary>private Hashtable hashtable = Hashtable.Synchronized(new Hashtable());? ? 在枚舉讀取時(shí),加lock,這里lock其同步對(duì)象SyncRoot?
/// <summary>/// 讀取/// </summary>public void Read(){ lock(hashtable.SyncRoot){foreach (var item in hashtable.Keys){Console.WriteLine("Key:{0}",item);}}}轉(zhuǎn)載于:https://www.cnblogs.com/bile/p/6114506.html
總結(jié)
以上是生活随笔為你收集整理的c# 变量,对象,静态类型,集合类的线程安全回顾的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 系统资源的观察
- 下一篇: 2017年你会花钱在线听歌吗?