第7章 多線程程序設(shè)計_第1頁
第7章 多線程程序設(shè)計_第2頁
第7章 多線程程序設(shè)計_第3頁
第7章 多線程程序設(shè)計_第4頁
第7章 多線程程序設(shè)計_第5頁
已閱讀5頁,還剩11頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

7.1線程的概念

7.2多線程程序設(shè)計

7.3多線程的狀態(tài)處理

7.4線程的同步與共享7.1線?程?的?概?念線程,有時被稱為輕量級進程(LightweightProcess,LWP),是程序執(zhí)行流的最小單元。一個標準的線程由線程ID、當前指令指針(PC)、寄存器集合和堆棧組成。另外,線程是進程中的一個實體,是被系統(tǒng)獨立調(diào)度和分派的基本單位,線程自己不擁有系統(tǒng)資源,只擁有運行中必需的資源,但它可與同屬一個進程的其他線程共享進程所擁有的全部資源。一個線程可以創(chuàng)建和撤消另一個線程,同一進程中的多個線程之間可以并發(fā)執(zhí)行。由于線程之間的相互制約,致使線程在運行中呈現(xiàn)出間斷性。線程也有就緒、阻塞和運行三種基本狀態(tài)。每一個程序至少有一個線程,若程序只有一個線程,那就是程序本身。7.1.1線程、進程和多任務(wù)現(xiàn)在的操作系統(tǒng)都是多任務(wù)操作系統(tǒng),每個運行的任務(wù)就是操作系統(tǒng)所做的一件事情,比如在聽歌的同時還在用MSN和好友聊天。聽歌和聊天就是兩個任務(wù),這個兩個任務(wù)是“同時”進行的。一個任務(wù)一般對應(yīng)一個進程,也可能包含好幾個進程。比如運行的MSN就對應(yīng)一個MSN的進程,如果用戶使用的是Windows系統(tǒng),就可以在任務(wù)管理器中看到操作系統(tǒng)正在運行的進程信息。一般來說,當運行一個應(yīng)用程序的時候,就啟動了一個進程,當然有些會啟動多個進程。啟動進程的時候,操作系統(tǒng)會為進程分配資源,其中最主要的資源是內(nèi)存空間,因為程序是在內(nèi)存中運行的。在進程中,有些程序流程塊是可以亂序執(zhí)行的,并且這個流程塊可以同時被多次執(zhí)行。實際上,這樣的流程塊就是線程體。線程是進程中亂序執(zhí)行的代碼流程。當多個線程同時運行的時候,這樣的執(zhí)行模式就成為并發(fā)執(zhí)行。線程與進程的比較如下:(1)進程:每個進程都有獨立的代碼和數(shù)據(jù)空間(進程上下文),進程切換的開銷大。(2)線程:即輕量的進程,同一類線程共享代碼和數(shù)據(jù)空間。每個線程有獨立的運行棧和程序計數(shù)器(PC),線程切換的開銷小。(3)多進程:在操作系統(tǒng)中能同時運行多個任務(wù)程序。(4)多線程:在同一應(yīng)用程序中有多個順序流同時執(zhí)行。7.1.2Java中的多線程多線程機制是Java語言的又一重要特征,使用多線程技術(shù)可以使系統(tǒng)同時運行多個執(zhí)行體,這樣可以加快程序的響應(yīng)時間,提高計算機資源的利用率。使用多線程技術(shù)可以提高整個應(yīng)用系統(tǒng)的性能。在Java中,創(chuàng)建線程有兩種方法:一種是通過創(chuàng)建Thread類的子類來實現(xiàn);另一種是通過實現(xiàn)Runnable接口的類來實現(xiàn)。7.2多線程程序設(shè)計7.2.1從Thread類繼承從Thread類繼承是創(chuàng)建一個線程較為簡便的方法。在繼承這個類之后,我們需要覆蓋它的run方法,每一個線程都會分別執(zhí)行一次run方法。下面程序是一個多線程的實例。在這個程序中有兩個線程,每個線程都會執(zhí)行一次run方法,但是兩個線程執(zhí)行的順序并不固定,因此,輸出誰先誰后都是隨機的。程序后面是某一次運行的輸出(注意每次運行都會不同)。注意,創(chuàng)建線程后,start方法用于啟動線程。在一個方法中調(diào)用Thread.currentThread().getName()方法,可以獲取當前線程的名字。在mian方法中調(diào)用該方法,獲取的是主線程的名字。多線程程序是亂序執(zhí)行。因此,只有亂序執(zhí)行的代碼才有必要設(shè)計為多線程。Thread.sleep()方法的調(diào)用目的是不讓當前線程獨自占有該進程所獲取的CPU資源,以留出一定時間給其他線程執(zhí)行的機會。實際上所有的多線程代碼執(zhí)行順序都是不確定的,每次執(zhí)行的結(jié)果都是隨機的。7.2.2實現(xiàn)Runnable接口【示例7.2】通過接口構(gòu)造線程體。publicclassClockextendsjava.applet.AppletimplementsRunnable{ //實現(xiàn)接口ThreadclockThread;publicvoidstart(){//該方法是Applet的方法不是線程的方法if(clockThread==null){clockThread=newThread(this,"Clock");/*線程體是Clock對象本身線程名字為"Clock"*/clockThread.start(); //啟動線程}}

publicvoidrun(){ //run()方法中是線程執(zhí)行的內(nèi)容while(clockThread!=null){repaint(); //刷新顯示畫面try{clockThread.sleep(1000);//睡眠1秒即每隔1秒執(zhí)行一次}catch(InterruptedExceptione){}}}publicvoidpaint(Graphicsg){Datenow=newDate();//獲得當前的時間對象g.drawString(now.getHours()+":"+now.getMinutes()+":"+now.getSeconds(),5,10);//顯示當前時間}publicvoidstop(){//該方法是Applet的方法不是線程的方法clockThread.stop();clockThread=null;}}以上示例是通過每隔1秒就執(zhí)行線程的刷新畫面功能來顯示當前的時間;看起來的效果就是一個時鐘每隔1秒就變化一次。由于采用的是實現(xiàn)接口Runnable的方式,所以該類Clock還繼承了Applet,Clock就可以Applet的方式運行。構(gòu)造線程體的兩種方法的比較如下:(1)使用Runnable接口。①可以將CPU代碼和數(shù)據(jù)分開,從而形成清晰的模型。②可以從其他類繼承。③保持程序風格的一致性。(2)直接繼承Thread類。①不能從其他類繼承。②編寫簡單,可以直接操作線程無需使用Thread.currentThread()。7.3多線程的狀態(tài)處理7.3.1線程的狀態(tài)線程的狀態(tài)可分為就緒、運行、阻塞、死亡等。就緒:當線程創(chuàng)建之后,調(diào)用start方法,自動運行run方法。此時,線程獲得了系統(tǒng)資源,并處于等待CPU的狀態(tài)。運行:線程獲得了CPU資源。阻塞:處于運行狀態(tài)的線程因為缺少某種資源而不得不停止運行,進入阻塞狀態(tài)。死亡:線程的run方法運行結(jié)束時,線程進入死亡狀態(tài)。7.3.2對線程狀態(tài)的控制1.終止線程線程終止后其生命周期也就結(jié)束了,即進入死亡狀態(tài),終止后的線程不能再被調(diào)度執(zhí)行。以下是進入死亡狀態(tài)的幾種情況線程:(1)線程執(zhí)行完其run()方法后會自然終止。(2)通過調(diào)用線程的實例方法stop()來終止線程。2.測試線程狀態(tài)可以通過Thread中的isAlive()方法來獲取線程是否處于活動狀態(tài)。3.線程的暫停和恢復(fù)有幾種方法可以暫停一個線程的執(zhí)行,并在適當?shù)臅r候再恢復(fù)其執(zhí)行。(1)?sleep()方法。當前線程睡眠(停止執(zhí)行),即若干毫秒線程由運行中狀態(tài),進入不可運行狀態(tài),停止執(zhí)行時間到后線程進入可運行狀態(tài)。(2)?suspend()和resume()方法。線程的暫停和恢復(fù)通過調(diào)用線程的suspend()方法使線程暫時由可運行態(tài)切換到不可運行態(tài),若此線程想再回到可運行態(tài),必須由其他線程調(diào)用resume()方法來實現(xiàn)。注:從JDK1.2開始就不再使用suspend()和resume()。(3)?join()方法。當前線程等待調(diào)用該方法的線程結(jié)束后,再恢復(fù)執(zhí)行。7.4線程的同步與共享因為多線程提供了程序的異步執(zhí)行的功能,可能會出現(xiàn)兩個或多個線程同時訪問共享資源,所以在必要時還必須提供一種同步機制。線程同步可以確保當兩個或多個線程需要訪問共享資源時,一次只有一個線程使用資源。7.4.1線程的同步1.線程的同步機制在Java中,使用synchronized關(guān)鍵字修飾的方法稱為同步方法。當某一線程在一個同步方法中執(zhí)行的時候,其他所有企圖調(diào)用同步方法的線程或者其他方法都必須等待。在Java中使用synchronized的兩種方式如下:(1)放在方法前面,這樣調(diào)用該方法的線程均將獲得對象的鎖。(2)放在代碼塊前面,它也有以下兩種形式:synchronized(this){…}:代碼塊中的代碼將獲得當前對象引用的鎖。synchronized(otherObj){…}:代碼塊中的代碼將獲得指定對象引用的鎖。2.死鎖線程系統(tǒng)還存在一個更大的風險,即“死鎖”。死鎖是保護數(shù)據(jù)不受線程損壞的自然結(jié)果。如果共享資源有狀態(tài),而且在多個線程處于活動狀態(tài)時更改代碼塊的狀態(tài),則當多個線程運行時,就可能會潛在地破壞資源狀態(tài)。線程是獨立調(diào)度的,不一定按固定順序運行,這必然存在風險。要解決這個問題,應(yīng)將數(shù)據(jù)設(shè)置為私有,并同步代碼塊。但是,如果在應(yīng)用程序中定義同步代碼,則可能出現(xiàn)死鎖。具體地講,對于兩個已經(jīng)有鎖標記的線程而言,如果它們都試圖調(diào)用受另一個線程的鎖標記保護的同步代碼,則可能出現(xiàn)死鎖。在出現(xiàn)死鎖時,兩個線程將永不能再運行。另外,調(diào)用使用相同鎖標記的方法的其他線程也將出現(xiàn)死鎖。當以下四個條件同時滿足時,就會發(fā)生死鎖:(1)互斥條件。線程使用的資源中至少有一個是不能共享的。(2)至少有一個進程必須有一個資源且正在等待獲取一個當前被別的進程持有的資源。(3)資源不能被進程搶占。所有的進程必須把資源釋放當作普通事件。(4)必須有循環(huán)等待。一個進程等待其他進程所持有的資源,這時,后者又在等待另一個進程所持有的資源,這樣直到有一個進程在等待第一個進程所持有的資源,使大家都被鎖住。所以,要防止死鎖發(fā)生,只需破壞其中一個條件即可

溫馨提示

  • 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)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論