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

下載本文檔

版權(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ì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論