Java與C#多線程的不同與常用模式轉(zhuǎn)換_第1頁
Java與C#多線程的不同與常用模式轉(zhuǎn)換_第2頁
Java與C#多線程的不同與常用模式轉(zhuǎn)換_第3頁
Java與C#多線程的不同與常用模式轉(zhuǎn)換_第4頁
Java與C#多線程的不同與常用模式轉(zhuǎn)換_第5頁
已閱讀5頁,還剩12頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第第頁Java與C#多線程的不同與常用模式轉(zhuǎn)換Java與C#多線程的不同與常用模式轉(zhuǎn)換

發(fā)表于:2023-05-26來源::點(diǎn)擊數(shù):標(biāo)簽:

線程是允許進(jìn)行并行計算的一個抽象概念:在另一個線程完成計算任務(wù)的同時,一個線程可以對圖像進(jìn)行更新,二個線程可以同時處理同一個進(jìn)程發(fā)出的二個網(wǎng)絡(luò)請求。我們在這篇文章中將重點(diǎn)討論Java和C#在線程方面的不同之處,并將一些Java中線程的常用模式轉(zhuǎn)換

線程是允許進(jìn)行并行計算的一個抽象概念:在另一個線程完成計算任務(wù)的同時,一個線程可以對圖像進(jìn)行更新,二個線程可以同時處理同一個進(jìn)程發(fā)出的二個網(wǎng)絡(luò)請求。我們在這篇文章中將重點(diǎn)討論Java和C#在線程方面的不同之處,并將一些Java中線程的常用模式轉(zhuǎn)換為C#。

從概念上講,線程提供了一種在一個軟件中并行執(zhí)行代碼的方式━━每個線程都“同時”在一個共享的內(nèi)存空間中執(zhí)行指令,(當(dāng)然是在一個處理器上,這是通過處于運(yùn)行狀態(tài)的線程的交替執(zhí)行完成的。),因此,每個線程都可以訪問一個程序內(nèi)的數(shù)據(jù)結(jié)構(gòu)。由于這種原因,多線程編程的難度就可想而知了,因?yàn)橐粋€程序內(nèi)有許多不同的線程需要安全地共享數(shù)據(jù)。

線程的創(chuàng)建和運(yùn)行

Java在java.lang.Thread和java.lang.Runnable類中提供了大部分的線程功能。創(chuàng)建一個線程非常簡單,就是擴(kuò)展Thread類,并調(diào)用start()。通過創(chuàng)建一個執(zhí)行Runnable()的類,并將該類作為參數(shù)傳遞給Thread(),也可以定義一個線程。仔細(xì)地閱讀下面這個簡單的Java程序,其中有2個線程同時在從1數(shù)到5,并將結(jié)果打印出來。

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二個類將上述的Java程序轉(zhuǎn)換為C#語言:

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+"");

}

}

這個例子中有一些小技巧。Java允許擴(kuò)展java.lang.Thread類和執(zhí)行java.lang.Runnable接口,C#則沒有為我們提供這些便利。一個C#中的Thread對象是不可知的,必須通過ThreadStart進(jìn)行創(chuàng)建,這意味著不能使用內(nèi)部的類模式,而必須創(chuàng)建一個對象,而且必須傳遞給線程一個對象的方法供線程執(zhí)行用。

線程的使用

Java中存在許多編程人員希望能夠?qū)€程使用的標(biāo)準(zhǔn)操作:例如,測試線程是否存在、加入一個線程直到它死亡、殺死一個線程等。

表1:線程管理的函數(shù)

Java中java.lang.Thread中的方法和C#中System.Threading.Thread對象的對比。

setDaemon(booleanon)方法

IsBackground設(shè)置屬性值

使一個存在的進(jìn)程成為一個新線程(如果剩下的所有進(jìn)程都成了新線程,程序?qū)⑼V惯\(yùn)行)。

isDaemon()方法

IsBackground獲取屬性

如果該線程是一個后臺線程,則返回真值。

isAlive()方法

IsAlive獲取屬性

如果該線程處于活動狀態(tài),則返回真值。

interrupt()方法

Interrupt()方法

盡管在Java中這一方法可以用來設(shè)置線程的中斷狀態(tài),而且可以用來檢查線程是否被中斷。在C#中沒有相應(yīng)的方法,對一個沒有處于阻塞狀態(tài)的線程執(zhí)行Interrupt方法將使下一次阻塞調(diào)用自動失效。

isInterrupted()方法

n/a

如果該線程處于阻塞狀態(tài),則返回真值。

sleep(longmillis)和sleep(longmillis,intnanos)

Sleep(intmillisecondTimeout)andSleep(System.TimeSpan)方法

使正在執(zhí)行的線程暫停一段給定的時間,或直到它被中斷。這一方法將在Java中將產(chǎn)生一個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è)定不同的是,在C#語言中則依據(jù)線程停止運(yùn)行是由于線程死亡(返回真)或是超時(返回假)而返回一個布爾型變量。

suspend()方法

Suspend()方法

二者的功能相同。這一方法容易引起死循環(huán),如果一個占有系統(tǒng)關(guān)健資源的線程被掛起來,則在這一線程恢復(fù)運(yùn)行之前,其他的線程不能訪問該資源。

resume()方法

Resume()方法

恢復(fù)一個被掛起的線程。

stop()方法

Abort()方法

參見下面的“線程停止”部分。

(特別說明,在上面的表中,每個小節(jié)的第一行是java中的方法,第二行是C#中的方法,第三行是有關(guān)的解釋,由于在文本文件中不能組織表格,請編輯多費(fèi)點(diǎn)心組織表格,原文中有表格的格式。)

線程的中止

由于能夠在沒有任何征兆的情況下使運(yùn)行的程序進(jìn)入一種混亂的狀態(tài),Java中的Thread.stop受到了普遍的反對。根據(jù)所調(diào)用的stop()方法,一個未經(jīng)檢查的java.lang.ThreadDeath錯誤將會破壞正在運(yùn)行著的程序的棧,隨著它的不斷運(yùn)行,能夠解除任何被鎖定的對象。由于這些鎖被不分青紅皂白地被打開,由它們所保護(hù)的數(shù)據(jù)就非??赡芟萑牖靵y狀態(tài)中。

根據(jù)當(dāng)前的Java文檔,推薦的中止一個線程的方法是讓運(yùn)行的線程檢查一個由其他的線程能夠改變的變量,該變量代表一個“死亡時間”條件。下面的程序就演示了這種方法。

//條件變量

privatebooleantimeToDie=false;

//在每次迭代中對條件變量進(jìn)行檢查。

classStoppableRunnable

extendsRunnable{

publicvoidrun(){

while(!timeToDie){

//進(jìn)行相應(yīng)的操作

}

}

}

上述的討論對C#中的Abort方法也適合。根據(jù)調(diào)用的Abort方法,令人捉摸不定的System.Threading.ThreadAbortException可能會破壞線程的棧,它可能釋放線程保持的一些變量,使處于保護(hù)狀態(tài)中的數(shù)據(jù)結(jié)構(gòu)出現(xiàn)不可預(yù)測的錯誤。我建議使用與上面所示的相似的方法來通知一個應(yīng)該死亡的線程。

線程的同步

從概念上來看,線程非常易于理解,實(shí)際上,由于他們可能交互地對同一數(shù)據(jù)結(jié)構(gòu)進(jìn)行操作,因此它們成為了令編程人員頭疼的一種東西。以本文開始的ThreadingExample為例,當(dāng)它運(yùn)行時,會在控制臺上輸出多種不同的結(jié)果。從1234512345到1122334455或1212334545在內(nèi)的各種情況都是可能出現(xiàn)的,輸出結(jié)果可能與操作系統(tǒng)的線程調(diào)度方式之間的差別有關(guān)。有時,需要確保只有一個線程能夠訪問一個給定的數(shù)據(jù)結(jié)構(gòu),以保證數(shù)據(jù)結(jié)構(gòu)的穩(wěn)定,這也是我們需要線程同步機(jī)制的原因所在。

為了保證數(shù)據(jù)結(jié)構(gòu)的穩(wěn)定,我們必須通過使用“鎖”來調(diào)整二個線程的操作順序。二種語言都通過對引用的對象申請一個“鎖”,一旦一段程序獲得該“鎖”的控制權(quán)后,就可以保證只有它獲得了這個“鎖”,能夠?qū)υ搶ο筮M(jìn)行操作。同樣,利用這種鎖,一個線程可以一直處于等待狀態(tài),直到有能夠喚醒它信號通過變量傳來為止。

表2:線程同步

需要對線程進(jìn)行同步時需要掌握的關(guān)健字

synchronized

lock

C#中的lock命令實(shí)際上是為使用System.Threading.Monitor類中的Enter和Exit方法的語法上的準(zhǔn)備

Object.wait()

Monitor.Wait(objectobj)

C#中沒有等待對象的方法,如果要等待一個信號,則需要使用System.Threading.Monitor類,這二個方法都需要在同步的程序段內(nèi)執(zhí)行。

Object.notify()

Monitor.Pulse(objectobj)

參見上面的Monitor.Wait的解釋。

Object.notify()

Monitor.PulseAll(objectobj)

參見上面的Monitor.Wait的解釋。

(特別說明,在上面的表中,每個小節(jié)的第一行是java中的方法,第二行是C#中的方法,第三行是有關(guān)的解釋,由于在文本文件中不能組織表格,請編輯多費(fèi)點(diǎn)心組織表格,原文中有表格的格式。)

我們可以對上面的例子進(jìn)行一些適當(dāng)?shù)男薷?,通過首先添加一個進(jìn)行同步的變量,然后對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){

}

}

}

}

作了上述的改變后,每次只有一個線程(因?yàn)橐淮沃荒苡幸粋€線程獲得synchronizeVariable)能夠執(zhí)行forloop循環(huán)輸出數(shù)字1;然后,它會喚醒所有等待synchronizeVariable的線程(盡管現(xiàn)在還沒有線程處于等待狀態(tài)。),并試圖獲得被鎖著的變量,然后等待再次獲得鎖變量;下一個線程就可以開始執(zhí)行forloop循環(huán)輸出數(shù)字1,調(diào)用notifyAll()喚醒前面的線程,并使它開始試圖獲得synchronizeVariable變量,使自己處于等待狀態(tài),釋放synchronizeVariable,允許前面的線程獲得它。這個循環(huán)將一直進(jìn)行下去,直到它們都輸出完從1到5的數(shù)字。

通過一些簡單的語法變化可以將上述的修改在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#中特有的線程功能

象我們一直對C#所抱的期望那樣,C#中確實(shí)有一些Java不支持的方法、類和函數(shù),對于鐵桿的Java線程編程人員而言,這可是一件好事,因?yàn)樗麄兛梢杂肅#編寫代碼,然后在Java代碼中引用。

Enter/TryEnter/Exit

要在Java中獲得某一變量的鎖,必須在代碼的首尾二端加上synchronized關(guān)健字,指明需要獲得鎖的對象。一旦線程開始執(zhí)行synchronized塊中的代碼,它就獲得了對這一對象的鎖的控制權(quán)。同樣,一旦線程已經(jīng)離開了synchronized塊,它也將釋放這一對象的鎖。我們已經(jīng)知道,C#也有一個相似的被稱作lock的關(guān)健字。除了lock這個關(guān)健字外,C#還提供了內(nèi)置的獲得和釋放鎖的方法:Monitor.Enter(objectobj)和Monitor.Exit(objectobj),通過使用這些方法,編程人員可以獲得與使用lock相同的作用,但提供了更精確的控制方法。例如,可以在一個方法中鎖定幾個變量,而不同時或在代碼中的不同部分釋放它們。

對一個需要進(jìn)行同步的對象執(zhí)行System.Threading.Monitor.Enter操作將使線程獲得該對象的鎖,或者在由其他線程控制著該對象的鎖時進(jìn)行阻塞。通過執(zhí)行Monitor.Exit方法就可以釋放鎖,如果線程已經(jīng)不控制著該對象的鎖了,這一方法將會產(chǎn)生一個System.Threading.SynchronizationLockException異常信號。

C#中的Monitor類不但包括Enter方法,還包括TryEnter方法,如果執(zhí)行該方法,就會或者獲得一個鎖,或者返回一個表明它不能獲得鎖的返回值。

原子操作

System.Threading.Interlocked類提供了程序?qū)τ蓭讉€線程共享的變量進(jìn)行同步訪問的能力,C#把一些操作抽象為“原子”操作或“不可分割”的操作。為了說明這一問題是如何解決的,我們來看一下下面的Java代碼:

publicstaticintx=1;

publicstaticvoidincrement(){

x=x+1;

}

如果有二個不同的線程同時調(diào)用increment(),x最后的值可能是2或3,發(fā)生這種情況的原因可能是二個進(jìn)程無序地訪問x變量,在沒有將x置初值時對它執(zhí)行加1操作;在任一線程有機(jī)會對x執(zhí)行加1操作之前,二個線程都可能將x讀作1,并將它設(shè)置為新的值。

在Java和C#中,我們都可以實(shí)現(xiàn)對x變量的同步訪問,所有進(jìn)程都可以按各自的方式運(yùn)行。但通過使用Interlocked類,C#提供了一個對這一問題更徹底的解決方案。Interlocked類有一些方法,例如Increment(refintlocation)、Decrement(refintlocation),這二個方法都取得整數(shù)型參數(shù),對該整數(shù)執(zhí)行加或減1操作,并返回新的值,所有這些操作都以“不可分割的”方式進(jìn)行,這樣就無需單獨(dú)創(chuàng)建一個可以進(jìn)行同步操作的對象,如下例所示:

publicstaticObjectlocker=...

publicstaticintx

溫馨提示

  • 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)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論