版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第第頁(yè)Java與C#多線程的不同與常用模式轉(zhuǎn)換Java與C#多線程的不同與常用模式轉(zhuǎn)換
發(fā)表于:2023-05-26來(lái)源::點(diǎn)擊數(shù):標(biāo)簽:
線程是允許進(jìn)行并行計(jì)算的一個(gè)抽象概念:在另一個(gè)線程完成計(jì)算任務(wù)的同時(shí),一個(gè)線程可以對(duì)圖像進(jìn)行更新,二個(gè)線程可以同時(shí)處理同一個(gè)進(jìn)程發(fā)出的二個(gè)網(wǎng)絡(luò)請(qǐng)求。我們?cè)谶@篇文章中將重點(diǎn)討論Java和C#在線程方面的不同之處,并將一些Java中線程的常用模式轉(zhuǎn)換
線程是允許進(jìn)行并行計(jì)算的一個(gè)抽象概念:在另一個(gè)線程完成計(jì)算任務(wù)的同時(shí),一個(gè)線程可以對(duì)圖像進(jìn)行更新,二個(gè)線程可以同時(shí)處理同一個(gè)進(jìn)程發(fā)出的二個(gè)網(wǎng)絡(luò)請(qǐng)求。我們?cè)谶@篇文章中將重點(diǎn)討論Java和C#在線程方面的不同之處,并將一些Java中線程的常用模式轉(zhuǎn)換為C#。
從概念上講,線程提供了一種在一個(gè)軟件中并行執(zhí)行代碼的方式━━每個(gè)線程都“同時(shí)”在一個(gè)共享的內(nèi)存空間中執(zhí)行指令,(當(dāng)然是在一個(gè)處理器上,這是通過(guò)處于運(yùn)行狀態(tài)的線程的交替執(zhí)行完成的。),因此,每個(gè)線程都可以訪問(wèn)一個(gè)程序內(nèi)的數(shù)據(jù)結(jié)構(gòu)。由于這種原因,多線程編程的難度就可想而知了,因?yàn)橐粋€(gè)程序內(nèi)有許多不同的線程需要安全地共享數(shù)據(jù)。
線程的創(chuàng)建和運(yùn)行
Java在java.lang.Thread和java.lang.Runnable類中提供了大部分的線程功能。創(chuàng)建一個(gè)線程非常簡(jiǎn)單,就是擴(kuò)展Thread類,并調(diào)用start()。通過(guò)創(chuàng)建一個(gè)執(zhí)行Runnable()的類,并將該類作為參數(shù)傳遞給Thread(),也可以定義一個(gè)線程。仔細(xì)地閱讀下面這個(gè)簡(jiǎn)單的Java程序,其中有2個(gè)線程同時(shí)在從1數(shù)到5,并將結(jié)果打印出來(lái)。
publicclassThreadingExample
extendsObject{
publicstaticvoidmain(Stringargs[]){
Thread[]threads=newThread[2];
for(intcount=1;count=threads.length;count++){
threads[count]=newThread(newRunnable(){
publicvoidrun(){
count();
}
});
threads[count].start();
}
}
publicstaticvoidcount(){
for(intcount=1;count=5;count++)
System.out.print(count+"");
}
}
我們可以使用System.Threading.Thread和System.Threading.ThreadStart二個(gè)類將上述的Java程序轉(zhuǎn)換為C#語(yǔ)言:
usingSystem.Threading;
publicclassThreadingExample:Object{
publicstaticvoidMain(){
Thread[]threads=newThread[2];
for(intcount=1;count=threads.Length;count++){
threads[count]=newThread(newThreadStart(Count));
threads[count].Start();
}
}
publicstaticvoidCount(){
for(intcount=1;count=5;count++)
Console.Write(count+"");
}
}
這個(gè)例子中有一些小技巧。Java允許擴(kuò)展java.lang.Thread類和執(zhí)行java.lang.Runnable接口,C#則沒(méi)有為我們提供這些便利。一個(gè)C#中的Thread對(duì)象是不可知的,必須通過(guò)ThreadStart進(jìn)行創(chuàng)建,這意味著不能使用內(nèi)部的類模式,而必須創(chuàng)建一個(gè)對(duì)象,而且必須傳遞給線程一個(gè)對(duì)象的方法供線程執(zhí)行用。
線程的使用
Java中存在許多編程人員希望能夠?qū)€程使用的標(biāo)準(zhǔn)操作:例如,測(cè)試線程是否存在、加入一個(gè)線程直到它死亡、殺死一個(gè)線程等。
表1:線程管理的函數(shù)
Java中java.lang.Thread中的方法和C#中System.Threading.Thread對(duì)象的對(duì)比。
setDaemon(booleanon)方法
IsBackground設(shè)置屬性值
使一個(gè)存在的進(jìn)程成為一個(gè)新線程(如果剩下的所有進(jìn)程都成了新線程,程序?qū)⑼V惯\(yùn)行)。
isDaemon()方法
IsBackground獲取屬性
如果該線程是一個(gè)后臺(tái)線程,則返回真值。
isAlive()方法
IsAlive獲取屬性
如果該線程處于活動(dòng)狀態(tài),則返回真值。
interrupt()方法
Interrupt()方法
盡管在Java中這一方法可以用來(lái)設(shè)置線程的中斷狀態(tài),而且可以用來(lái)檢查線程是否被中斷。在C#中沒(méi)有相應(yīng)的方法,對(duì)一個(gè)沒(méi)有處于阻塞狀態(tài)的線程執(zhí)行Interrupt方法將使下一次阻塞調(diào)用自動(dòng)失效。
isInterrupted()方法
n/a
如果該線程處于阻塞狀態(tài),則返回真值。
sleep(longmillis)和sleep(longmillis,intnanos)
Sleep(intmillisecondTimeout)andSleep(System.TimeSpan)方法
使正在執(zhí)行的線程暫停一段給定的時(shí)間,或直到它被中斷。這一方法將在Java中將產(chǎn)生一個(gè)java.lang.InterruptedException狀態(tài),在C#中將產(chǎn)生System.Threading.ThreadInterruptedException狀態(tài)。
join()、join(longmillis)和join(longmillis,intnanos)方法
Join()、Join(intmillisecondTimeout)和Join(System.TimeSpan)方法與Java中僅依靠超時(shí)設(shè)定不同的是,在C#語(yǔ)言中則依據(jù)線程停止運(yùn)行是由于線程死亡(返回真)或是超時(shí)(返回假)而返回一個(gè)布爾型變量。
suspend()方法
Suspend()方法
二者的功能相同。這一方法容易引起死循環(huán),如果一個(gè)占有系統(tǒng)關(guān)健資源的線程被掛起來(lái),則在這一線程恢復(fù)運(yùn)行之前,其他的線程不能訪問(wèn)該資源。
resume()方法
Resume()方法
恢復(fù)一個(gè)被掛起的線程。
stop()方法
Abort()方法
參見下面的“線程停止”部分。
(特別說(shuō)明,在上面的表中,每個(gè)小節(jié)的第一行是java中的方法,第二行是C#中的方法,第三行是有關(guān)的解釋,由于在文本文件中不能組織表格,請(qǐng)編輯多費(fèi)點(diǎn)心組織表格,原文中有表格的格式。)
線程的中止
由于能夠在沒(méi)有任何征兆的情況下使運(yùn)行的程序進(jìn)入一種混亂的狀態(tài),Java中的Thread.stop受到了普遍的反對(duì)。根據(jù)所調(diào)用的stop()方法,一個(gè)未經(jīng)檢查的java.lang.ThreadDeath錯(cuò)誤將會(huì)破壞正在運(yùn)行著的程序的棧,隨著它的不斷運(yùn)行,能夠解除任何被鎖定的對(duì)象。由于這些鎖被不分青紅皂白地被打開,由它們所保護(hù)的數(shù)據(jù)就非常可能陷入混亂狀態(tài)中。
根據(jù)當(dāng)前的Java文檔,推薦的中止一個(gè)線程的方法是讓運(yùn)行的線程檢查一個(gè)由其他的線程能夠改變的變量,該變量代表一個(gè)“死亡時(shí)間”條件。下面的程序就演示了這種方法。
//條件變量
privatebooleantimeToDie=false;
//在每次迭代中對(duì)條件變量進(jìn)行檢查。
classStoppableRunnable
extendsRunnable{
publicvoidrun(){
while(!timeToDie){
//進(jìn)行相應(yīng)的操作
}
}
}
上述的討論對(duì)C#中的Abort方法也適合。根據(jù)調(diào)用的Abort方法,令人捉摸不定的System.Threading.ThreadAbortException可能會(huì)破壞線程的棧,它可能釋放線程保持的一些變量,使處于保護(hù)狀態(tài)中的數(shù)據(jù)結(jié)構(gòu)出現(xiàn)不可預(yù)測(cè)的錯(cuò)誤。我建議使用與上面所示的相似的方法來(lái)通知一個(gè)應(yīng)該死亡的線程。
線程的同步
從概念上來(lái)看,線程非常易于理解,實(shí)際上,由于他們可能交互地對(duì)同一數(shù)據(jù)結(jié)構(gòu)進(jìn)行操作,因此它們成為了令編程人員頭疼的一種東西。以本文開始的ThreadingExample為例,當(dāng)它運(yùn)行時(shí),會(huì)在控制臺(tái)上輸出多種不同的結(jié)果。從1234512345到1122334455或1212334545在內(nèi)的各種情況都是可能出現(xiàn)的,輸出結(jié)果可能與操作系統(tǒng)的線程調(diào)度方式之間的差別有關(guān)。有時(shí),需要確保只有一個(gè)線程能夠訪問(wèn)一個(gè)給定的數(shù)據(jù)結(jié)構(gòu),以保證數(shù)據(jù)結(jié)構(gòu)的穩(wěn)定,這也是我們需要線程同步機(jī)制的原因所在。
為了保證數(shù)據(jù)結(jié)構(gòu)的穩(wěn)定,我們必須通過(guò)使用“鎖”來(lái)調(diào)整二個(gè)線程的操作順序。二種語(yǔ)言都通過(guò)對(duì)引用的對(duì)象申請(qǐng)一個(gè)“鎖”,一旦一段程序獲得該“鎖”的控制權(quán)后,就可以保證只有它獲得了這個(gè)“鎖”,能夠?qū)υ搶?duì)象進(jìn)行操作。同樣,利用這種鎖,一個(gè)線程可以一直處于等待狀態(tài),直到有能夠喚醒它信號(hào)通過(guò)變量傳來(lái)為止。
表2:線程同步
需要對(duì)線程進(jìn)行同步時(shí)需要掌握的關(guān)健字
synchronized
lock
C#中的lock命令實(shí)際上是為使用System.Threading.Monitor類中的Enter和Exit方法的語(yǔ)法上的準(zhǔn)備
Object.wait()
Monitor.Wait(objectobj)
C#中沒(méi)有等待對(duì)象的方法,如果要等待一個(gè)信號(hào),則需要使用System.Threading.Monitor類,這二個(gè)方法都需要在同步的程序段內(nèi)執(zhí)行。
Object.notify()
Monitor.Pulse(objectobj)
參見上面的Monitor.Wait的解釋。
Object.notify()
Monitor.PulseAll(objectobj)
參見上面的Monitor.Wait的解釋。
(特別說(shuō)明,在上面的表中,每個(gè)小節(jié)的第一行是java中的方法,第二行是C#中的方法,第三行是有關(guān)的解釋,由于在文本文件中不能組織表格,請(qǐng)編輯多費(fèi)點(diǎn)心組織表格,原文中有表格的格式。)
我們可以對(duì)上面的例子進(jìn)行一些適當(dāng)?shù)男薷模ㄟ^(guò)首先添加一個(gè)進(jìn)行同步的變量,然后對(duì)count()方法進(jìn)行如下的修改,使變量在“鎖”中被執(zhí)行加1操作。
publicstaticObjectsynchronizeVariable="lockingvariable";
publicstaticvoidcount(){
synchronized(synchronizeVariable){
for(intcount=1;count=5;count++){
System.out.print(count+"");
synchronizeVariable.notifyAll();
if(count5)
try{
synchronizeVariable.wait();
}catch(InterruptedExceptionerror){
}
}
}
}
作了上述的改變后,每次只有一個(gè)線程(因?yàn)橐淮沃荒苡幸粋€(gè)線程獲得synchronizeVariable)能夠執(zhí)行forloop循環(huán)輸出數(shù)字1;然后,它會(huì)喚醒所有等待synchronizeVariable的線程(盡管現(xiàn)在還沒(méi)有線程處于等待狀態(tài)。),并試圖獲得被鎖著的變量,然后等待再次獲得鎖變量;下一個(gè)線程就可以開始執(zhí)行forloop循環(huán)輸出數(shù)字1,調(diào)用notifyAll()喚醒前面的線程,并使它開始試圖獲得synchronizeVariable變量,使自己處于等待狀態(tài),釋放synchronizeVariable,允許前面的線程獲得它。這個(gè)循環(huán)將一直進(jìn)行下去,直到它們都輸出完從1到5的數(shù)字。
通過(guò)一些簡(jiǎn)單的語(yǔ)法變化可以將上述的修改在C#中實(shí)現(xiàn):
publicstaticObjectsynchronizeVariable="lockingvariable";
publicstaticvoidcount(){
lock(synchronizeVariable){
for(intcount=1;count=5;count++){
System.out.print(count+"");
Monitor.PulseAll(synchronizeVariable);
if(count5)
Monitor.Wait(synchronizeVariable);
}
}
}
C#中特有的線程功能
象我們一直對(duì)C#所抱的期望那樣,C#中確實(shí)有一些Java不支持的方法、類和函數(shù),對(duì)于鐵桿的Java線程編程人員而言,這可是一件好事,因?yàn)樗麄兛梢杂肅#編寫代碼,然后在Java代碼中引用。
Enter/TryEnter/Exit
要在Java中獲得某一變量的鎖,必須在代碼的首尾二端加上synchronized關(guān)健字,指明需要獲得鎖的對(duì)象。一旦線程開始執(zhí)行synchronized塊中的代碼,它就獲得了對(duì)這一對(duì)象的鎖的控制權(quán)。同樣,一旦線程已經(jīng)離開了synchronized塊,它也將釋放這一對(duì)象的鎖。我們已經(jīng)知道,C#也有一個(gè)相似的被稱作lock的關(guān)健字。除了lock這個(gè)關(guān)健字外,C#還提供了內(nèi)置的獲得和釋放鎖的方法:Monitor.Enter(objectobj)和Monitor.Exit(objectobj),通過(guò)使用這些方法,編程人員可以獲得與使用lock相同的作用,但提供了更精確的控制方法。例如,可以在一個(gè)方法中鎖定幾個(gè)變量,而不同時(shí)或在代碼中的不同部分釋放它們。
對(duì)一個(gè)需要進(jìn)行同步的對(duì)象執(zhí)行System.Threading.Monitor.Enter操作將使線程獲得該對(duì)象的鎖,或者在由其他線程控制著該對(duì)象的鎖時(shí)進(jìn)行阻塞。通過(guò)執(zhí)行Monitor.Exit方法就可以釋放鎖,如果線程已經(jīng)不控制著該對(duì)象的鎖了,這一方法將會(huì)產(chǎn)生一個(gè)System.Threading.SynchronizationLockException異常信號(hào)。
C#中的Monitor類不但包括Enter方法,還包括TryEnter方法,如果執(zhí)行該方法,就會(huì)或者獲得一個(gè)鎖,或者返回一個(gè)表明它不能獲得鎖的返回值。
原子操作
System.Threading.Interlocked類提供了程序?qū)τ蓭讉€(gè)線程共享的變量進(jìn)行同步訪問(wèn)的能力,C#把一些操作抽象為“原子”操作或“不可分割”的操作。為了說(shuō)明這一問(wèn)題是如何解決的,我們來(lái)看一下下面的Java代碼:
publicstaticintx=1;
publicstaticvoidincrement(){
x=x+1;
}
如果有二個(gè)不同的線程同時(shí)調(diào)用increment(),x最后的值可能是2或3,發(fā)生這種情況的原因可能是二個(gè)進(jìn)程無(wú)序地訪問(wèn)x變量,在沒(méi)有將x置初值時(shí)對(duì)它執(zhí)行加1操作;在任一線程有機(jī)會(huì)對(duì)x執(zhí)行加1操作之前,二個(gè)線程都可能將x讀作1,并將它設(shè)置為新的值。
在Java和C#中,我們都可以實(shí)現(xiàn)對(duì)x變量的同步訪問(wèn),所有進(jìn)程都可以按各自的方式運(yùn)行。但通過(guò)使用Interlocked類,C#提供了一個(gè)對(duì)這一問(wèn)題更徹底的解決方案。Interlocked類有一些方法,例如Increment(refintlocation)、Decrement(refintlocation),這二個(gè)方法都取得整數(shù)型參數(shù),對(duì)該整數(shù)執(zhí)行加或減1操作,并返回新的值,所有這些操作都以“不可分割的”方式進(jìn)行,這樣就無(wú)需單獨(dú)創(chuàng)建一個(gè)可以進(jìn)行同步操作的對(duì)象,如下例所示:
publicstaticObjectlocker=...
publicstaticintx
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度出院患者出院后心理疏導(dǎo)服務(wù)協(xié)議書模板4篇
- 2025年版無(wú)子女無(wú)財(cái)產(chǎn)自愿離婚協(xié)議書定制版范本3篇
- 二零二五年度股份公司間互聯(lián)網(wǎng)+農(nóng)業(yè)合作框架協(xié)議范本3篇
- 二零二五年度智能化儲(chǔ)藏室租賃及維護(hù)服務(wù)協(xié)議范本4篇
- 2025年度美的中央空調(diào)銷售與智能化節(jié)能服務(wù)合同4篇
- 2025年度藝術(shù)品交易擔(dān)保合同4篇
- 2025年度個(gè)人小額貸款合同模板15篇
- 2025年續(xù)簽教育培訓(xùn)機(jī)構(gòu)合作協(xié)議意向書范本3篇
- 2025年度成立智能設(shè)備制造企業(yè)股權(quán)出資協(xié)議4篇
- 2025年度大型體育場(chǎng)館運(yùn)營(yíng)管理承包協(xié)議書模板4篇
- 《采礦工程英語(yǔ)》課件
- NB-T31045-2013風(fēng)電場(chǎng)運(yùn)行指標(biāo)與評(píng)價(jià)導(dǎo)則
- NB-T+10488-2021水電工程砂石加工系統(tǒng)設(shè)計(jì)規(guī)范
- 天津市和平區(qū)2023-2024學(xué)年七年級(jí)下學(xué)期6月期末歷史試題
- 《中電聯(lián)團(tuán)體標(biāo)準(zhǔn)-220kV變電站并聯(lián)直流電源系統(tǒng)技術(shù)規(guī)范》
- 微型消防站消防員培訓(xùn)內(nèi)容
- (完整版)鋼筋加工棚驗(yàn)算
- 焊接工藝的過(guò)程監(jiān)測(cè)與質(zhì)量分析
- 年夜飯營(yíng)養(yǎng)分析報(bào)告
- 華電行測(cè)題庫(kù)及答案2024
- 江西省萍鄉(xiāng)市2023-2024學(xué)年九年級(jí)上學(xué)期期末數(shù)學(xué)試題(含答案)
評(píng)論
0/150
提交評(píng)論