版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
第C#多線程之線程同步我們猜想一下程序的輸出結(jié)果是多少?2000?我們運行程序看一下輸出結(jié)果:
我們看到,程序最后輸出的結(jié)果跟我們預(yù)測的完全不一樣,這是什么原因呢?這就是由線程同步引起的問題。
線程同步問題:是解決多個線程同時操作一個資源的問題。
在上面的例子中,t1和t2兩個線程里面都是讓變量Counter的值自增1,假設(shè)這時t1線程讀取到Counter的值為200,可能t2線程執(zhí)行非常快,t1線程讀取Counter值的時候,t2線程已經(jīng)把Counter的值改為了205,等t1線程執(zhí)行完畢以后,Counter的值又被變?yōu)榱?01,這樣就會出現(xiàn)線程同步的問題了。那么該如何解決這個問題呢?
二、解決線程同步問題
1、lock
解決線程同步問題最簡單的是使用lock。lock可以解決多個線程同時操作一個資源引起的問題。lock是C#中的關(guān)鍵字,它要鎖定一個資源,lock的特點是:同一時刻只能有一個線程進入lock的對象的范圍,其它lock的線程都要等待。我們看下面優(yōu)化后的代碼:
usingSystem;
usingSystem.Threading;
namespaceThreadSynchDemo
classProgram
privatestaticintCounter=0;
//定義一個locker對象
privatestaticObjectlocker=newObject();
staticvoidMain(string[]args)
#region存在線程同步問題
//Threadt1=newThread(()={
//for(inti=0;i1000;i++)
//{
//Counter++;
//Thread.Sleep(1);
//}
//});
//t1.Start();
//Threadt2=newThread(()={
//for(inti=0;i1000;i++)
//{
//Counter++;
//Thread.Sleep(1);
//}
//});
//t2.Start();
#endregion
#region使用Lock解決線程同步問題
Threadt1=newThread(()={
for(inti=0;i1000;i++)
lock(locker)
Counter++;
Thread.Sleep(1);
t1.Start();
Threadt2=newThread(()={
for(inti=0;i1000;i++)
lock(locker)
Counter++;
Thread.Sleep(1);
t2.Start();
#endregion
Thread.Sleep(3000);
Console.WriteLine(Counter);
Console.ReadKey();
}
這時我們在運行程序,查看輸出結(jié)果:
這時輸出結(jié)果是正確的。
注意:lock只能鎖住同一個對象,如果是不同的對象,還是會有線程同步的問題。lock鎖定的對象必須是引用類型的對象。
我們在定義一個Object類型的對象,lock分別鎖住兩個對象,看看是什么結(jié)果:
usingSystem;
usingSystem.Threading;
namespaceThreadSynchDemo
classProgram
privatestaticintCounter=0;
//定義一個locker對象
privatestaticObjectlocker=newObject();
//定義locker2
privatestaticObjectlocker2=newObject();
staticvoidMain(string[]args)
#region存在線程同步問題
//Threadt1=newThread(()={
//for(inti=0;i1000;i++)
//{
//Counter++;
//Thread.Sleep(1);
//}
//});
//t1.Start();
//Threadt2=newThread(()={
//for(inti=0;i1000;i++)
//{
//Counter++;
//Thread.Sleep(1);
//}
//});
//t2.Start();
#endregion
#region使用Lock解決線程同步問題
//Threadt1=newThread(()={
//for(inti=0;i1000;i++)
//{
//lock(locker)
//{
//Counter++;
//}
//Thread.Sleep(1);
//}
//});
//t1.Start();
//Threadt2=newThread(()={
//for(inti=0;i1000;i++)
//{
//lock(locker)
//{
//Counter++;
//}
//Thread.Sleep(1);
//}
//});
//t2.Start();
#endregion
#region使用lock鎖住不同的對象也會有線程同步問題
Threadt1=newThread(()={
for(inti=0;i1000;i++)
lock(locker)
Counter++;
Thread.Sleep(1);
t1.Start();
Threadt2=newThread(()={
for(inti=0;i1000;i++)
lock(locker2)
Counter++;
Thread.Sleep(1);
t2.Start();
#endregion
Thread.Sleep(3000);
Console.WriteLine(Counter);
Console.ReadKey();
}
程序運行結(jié)果:
可以看到,這時還是會有線程同步的問題。雖然使用了lock,但是我們鎖住的是不同的對象,這樣也會有線程同步問題。lock必須鎖住同一個對象才可以。
我們下面在來看一個多線程同步問題的例子:
usingSystem;
usingSystem.Threading;
namespaceThreadSynchDemo2
classProgram
staticintMoney=100;
///summary
///定義一個取錢的方法
////summary
///paramname="name"/param
staticvoidQuQian(stringname)
Console.WriteLine(name+"查看一下余額"+Money);
intyue=Money-1;
Console.WriteLine(name+"取錢");
Money=yue;
Console.WriteLine(name+"取完了,剩"+Money);
staticvoidMain(string[]args)
Threadt1=newThread(()={
for(inti=0;ii++)
QuQian("t2");
Threadt2=newThread(()={
for(inti=0;ii++)
QuQian("t2");
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine("余額"+Money);
Console.ReadKey();
}
我們看一下輸出結(jié)果:
可以看到,最終的余額并不是80,這也是線程同步帶來的問題,如何解決。解決思路就是使用同步的技術(shù)避免兩個線程同時修改一個余額。
2、最大粒度同步方法
在方法上面使用[MethodImpl(MethodImplOptions.Synchronized)],標(biāo)記該方法是同步方法,這樣一個方法只能同時被一個線程訪問。我們在QuQian的方法上面標(biāo)記,修改后的代碼如下:
usingSystem;
usingSystem.Runtime.CompilerServices;
usingSystem.Threading;
namespaceThreadSynchDemo2
classProgram
staticintMoney=100;
///summary
///定義一個取錢的方法,在上面標(biāo)記為同步方法
////summary
///paramname="name"/param
[MethodImpl(MethodImplOptions.Synchronized)]
staticvoidQuQian(stringname)
Console.WriteLine(name+"查看一下余額"+Money);
intyue=Money-1;
Console.WriteLine(name+"取錢");
Money=yue;
Console.WriteLine(name+"取完了,剩"+Money);
staticvoidMain(string[]args)
Threadt1=newThread(()={
for(inti=0;ii++)
QuQian("t2");
Threadt2=newThread(()={
for(inti=0;ii++)
QuQian("t2");
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine("余額"+Money);
Console.ReadKey();
}
程序輸出結(jié)果:
現(xiàn)在的方法就是線程安全的了。什么是線程安全呢?線程安全是指方法可以被多個線程隨意調(diào)用,而不會出現(xiàn)混亂。如果出現(xiàn)了混亂,那么就是線程不安全的。線程安全的方法可以在多線程里面隨意的使用。
3、對象互斥鎖
對象互斥鎖就是我們上面講的lock。我們在用lock來修改上面QuQian的例子:
usingSystem;
usingSystem.Runtime.CompilerServices;
usingSystem.Threading;
namespaceThreadSynchDemo2
classProgram
staticintMoney=100;
///summary
///定義一個取錢的方法,在上面標(biāo)記為同步方法
////summary
///paramname="name"/param
//[MethodImpl(MethodImplOptions.Synchronized)]
//staticvoidQuQian(stringname)
//Console.WriteLine(name+"查看一下余額"+Money);
//intyue=Money-1;
//Console.WriteLine(name+"取錢");
//Money=yue;
//Console.WriteLine(name+"取完了,剩"+Money);
privatestaticobjectlocker=newobject();
staticvoidQuQian(stringname)
Console.WriteLine(name+"查看一下余額"+Money);
intyue=Money-1;
Console.WriteLine(name+"取錢");
Money=yue;
Console.WriteLine(name+"取完了,剩"+Money);
staticvoidMain(string[]args)
Threadt1=newThread(()={
for(inti=0;ii++)
//使用對象互斥鎖
lock(locker)
QuQian("t1");
Threadt2=newThread(()={
for(inti=0;ii++)
lock(locker)
QuQian("t2");
t1.Start();
t2.Start();
t1.Join();
t2.Join();
Console.WriteLine("余額"+Money);
Console.ReadKey();
}
程序輸出結(jié)果:
可以看到,最終的輸出結(jié)果還是80。
同一時刻只能有一個線程進入同一個對象的lock代碼塊。必須是同一個對象才能起到互斥的作用。lock后必須是引用類型,不一定是object,只要是對象就行。
鎖對象選擇很重要,選不對就起不到同步的作用;選不對還有可能會造成其他地方被鎖,比如用字符串做鎖(因為字符串緩沖池導(dǎo)致導(dǎo)致可能用的是其他地方正在使用的鎖),所以不建議使用字符串做鎖。下面的代碼就是不允許的:
lock("locker")
兩個方法如果都用一個對象做鎖,那么訪問A的時候就不能訪問B,因此鎖選擇很重要。
4、Monitor
其實lock關(guān)鍵字就是對Monitor的簡化調(diào)用,lock最終會被編譯成Monitor,因此一般不直接使用Monitor類,看下面代碼:
usingSystem;
usingSystem.Threading;
namespaceMonitorDemo
classProgram
staticintMoney=100;
privatestaticobjectlocker=newobject();
staticvoidQuQian(stringname)
//等待沒有人鎖定locker對象,就鎖定它,然后繼續(xù)執(zhí)行
Monitor.Enter(locker);
Console.WriteLine(name+"查看一下余額"+Money);
intyue=Money-1;
Console.WriteLine(name+"取錢");
Money=yue;
Console.WriteLine(name+"取完了,剩"+Money);
finally
//釋放locker對象的鎖
Monitor.Exit(locker);
staticvoidMain(string[]args)
Threadt1=newThread(()={
for(inti=0;ii++)
QuQian("t1");
Threadt2=newThread(()={
for(inti=0;ii++)
QuQian("t2");
t1.Start();
t2.Start();
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025廣東江門市城建集團有限公司公路運營分公司招聘1人備考題庫附答案
- 2025年中船凌久航信科技(武漢)有限公司招聘(公共基礎(chǔ)知識)測試題附答案
- 2025年哈爾濱日報社新媒體中心招聘若干人備考題庫附答案
- 2026浙江臺州職業(yè)技術(shù)學(xué)院高層次人才招聘38人筆試模擬試題及答案解析
- 2025廣東茂名市高州市人民政府辦公室選調(diào)公務(wù)員5人備考題庫附答案
- 2025年聊城臨清市人才回引(17人)備考題庫附答案
- 2025廣東河源東源縣衛(wèi)生健康局招聘高層次和急需緊缺人才35人(公共基礎(chǔ)知識)綜合能力測試題附答案
- 2026甘肅酒泉市敦煌市國有資產(chǎn)事務(wù)中心遴選市屬國有企業(yè)外部董事人才庫人選筆試備考試題及答案解析
- 2026甘肅銀行校園招聘筆試備考試題及答案解析
- 2025秋人教版道德與法治八年級上冊3.1網(wǎng)絡(luò)改變世界課件
- 工程維保三方合同
- 地鐵車輛檢修安全培訓(xùn)
- 造血干細胞移植臨床應(yīng)用和新進展課件
- GB/T 10802-2023通用軟質(zhì)聚氨酯泡沫塑料
- 黑布林英語閱讀初一年級16《柳林風(fēng)聲》譯文和答案
- 杰青優(yōu)青學(xué)術(shù)項目申報答辯PPT模板
- 宿舍入住申請書
- 深圳中核海得威生物科技有限公司桐城分公司碳13-尿素原料藥項目環(huán)境影響報告書
- 2023年全國高考體育單招文化考試數(shù)學(xué)試卷真題及答案
- GB/T 28733-2012固體生物質(zhì)燃料全水分測定方法
- GB/T 14404-2011剪板機精度
評論
0/150
提交評論