假設多個線程共享一個靜態變量,如果讓每個線程都執行相同的方法每次讓靜態變量自增1,這樣的做法線程安全嗎?能保證自增變量數據同步嗎?本篇體驗使用lock語句塊和Interlocked類型方法保證自增變量的數據同步。
□ 線程不安全、數據不同步的做法
class Program{static int sum = 0;static void Main(string[] args){Stopwatch watch = new Stopwatch();watch.Start();Parallel.For(0, Environment.ProcessorCount, i =>{for (int j = 0; j < 100000000; ++j){AddOne();}});watch.Stop();Console.WriteLine("sum={0},用了{1}", sum, watch.Elapsed);Console.ReadKey();}static void AddOne(){sum++;}}
○ 變量sum是靜態的,供所有線程共享
○ Parallel.For提供並行循環, Environment.ProcessorCount表示處理器的處理,如果有4個CPU,就做4組循環
我們發現,結果不是我們期望的400000000,也就是說,在這種情況下的靜態變量自增不是線程安全的,換句話說,無法保證共享數據的同步。
□ 通過lock語句塊保持數據同步
lock語句塊能保證在同一時間只有一個線程進入其中。class Program{static int sum = 0;private static readonly object o = new object();static void Main(string[] args){Stopwatch watch = new Stopwatch();watch.Start();Parallel.For(0, Environment.ProcessorCount, i =>{for (int j = 0; j < 100000000; ++j){AddOne();}});watch.Stop();Console.WriteLine("sum={0},用了{1}", sum, watch.Elapsed);Console.ReadKey();}static void AddOne(){lock (o){sum++;}}}
這一次,使用lock語句塊得到了預期的結果。
□ 使用Interlocked保持數據同步
對於int或long類型變量的自增,並且保證類型安全,可以使用Interlocked類。提供的方法包括:
○ int Interlocked.Increment(ref int location),自增1
○ long Interlocked.Increment(ref long location),自增1
○ int Interlocked.Decrement(ref int location),自減1
○ long Interlocked.Decrement(ref long location),自減1
○ int Interlocked.Add(ref int location, int value),自增一個值
○ long Interlocked.Add(ref long location, long value),自增一個值
class Program{static int sum = 0;static void Main(string[] args){Stopwatch watch = new Stopwatch();watch.Start();Parallel.For(0, Environment.ProcessorCount, i =>{for (int j = 0; j < 100000000; ++j){AddOne();}});watch.Stop();Console.WriteLine("sum={0},用了{1}", sum, watch.Elapsed);Console.ReadKey();}static void AddOne(){Interlocked.Increment(ref sum);}}
使用Interlocked也能保證線程安全、數據同步,但耗時較長。
總結:
○ lock語句塊和Interlocked類型方法都能保證自增變量的線程安全、數據同步
○ Interlocked類型方法只適用於int,long類型變量,有一定的局限性
線程系列包括:
補充回復:
select
現金支付數量=(select count(*) as from test where type=1),
現金支付金額=(select sum(*) from test where type=1
),
銀行支付數量=(select count(*) from test where type=2
)
,銀行支付金額=(select count(*) from test where type=2
)
1,多線程有哪幾種方法
1。當一個線程進入moniter(也就是說站用一個object),另一個線程只有等待或返回,而我們把返回就稱為一種模式,這種模式的英文是Balking。
2。這兩個線程可以是有序的執行,而不是讓OS來調度,這時我們要用一個object來調度,這種模式稱為Scheduler。(這個詞及其含義其實OS中就有)。
3。如果這兩個線程同時讀一個資源,我們可以讓他們執行,但如果同時寫的話,你閉著眼睛都會知道可能出現問題,這時我們就要用另一種模式(Read/Write Lock)。
4。如果一個線程是為另一個線程服務的話,比如IE中負責數據傳輸的線程和界面顯示的線程,當一個圖片沒有傳完時,另一個線程就無法顯示,至少是部分沒有傳完。那麼這時我們要用一個模式稱為生產者和消費者,英文是Producer-Consumer。
5。兩個線程的消亡也可以不是完全又OS來控制的,這時我們需要給出一個條件,使得每個線程在符合條件是才消亡,也就是有序的消亡,我們稱為Two-Phase Termination。
同步有哪幾種方法
一、volatile關鍵字
volatile是最簡單的一種同步方法,當然簡單是要付出代價的。它只能在變量一級做同步,volatile的含義就是告訴處理器, 不要將我放入工作內存, 請直接在主存操作我。(【轉自 】)因此,當多線程同時訪問該變量時,都將直接操作主存,從本質上做到了變量共享。
二、lock關鍵字
lock是一種比較好用的簡單的線程同步方式,它是通過為給定對象獲取互斥鎖來實現同步的。它可以保證當一個線程在關鍵代碼段的時候,另一個線程不會進來,它只能等待,等到那個線程對象被釋放,也就是說線程出了臨界區。用法:
三、System.Threading.Interlocked
對於整數數據類型的簡單操作,可以用 Interlocked 類的成員來實現線程同步,存在於System.Threading命名空間。Interlocked類有以下方法:Increment , Decrement , Exchange 和CompareExchange 。使用Increment 和Decrement 可以保證對一個整數的加減為一個原子操作。Exchange 方法自動交換指定變量的值。CompareExchange 方法組合了兩個操作:比較兩個值以及根據比較的結果將第三個值存儲在其中一個變量中。比較和交換操作也是按原子操作執行的。如:
2,xml有哪幾種訪問方式
這道題你去搜吧 我很討厭這類問題 有幾種訪問方式?知道怎麼去讀,怎麼最優化地去讀就好了 要知道那麼多訪問方式干嘛呢。。
3,SQL,表test:
現金支付數量
select count(*) from test where type=1
現金支付金額
select sum(*) from test where type=1
銀行支付數量
select count(*) from test where type=......余下全文>>
在java中除了8中基本數據類型,其余的參數傳遞全部是引用傳遞
你只定義一了lock,當然四個線程都是使用了同一個lock
因此lock可以當做"鎖"來使用
每個線程執行到synchronized (lock)時,都會去申請lock的鎖(每個對象都有一個唯一的鎖)
申請到了才能執行synchronized 語句塊裡的內容,執行完了會釋放lock的鎖
沒有申請到鎖的線程會等待(lock有一個等待隊列),處於阻塞狀態,當有線程用完了鎖就會喚醒一個在等待lock鎖的一個線程...