java課程第10講_第1頁
java課程第10講_第2頁
java課程第10講_第3頁
java課程第10講_第4頁
java課程第10講_第5頁
已閱讀5頁,還剩28頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

1、第第9講講 多線程編程多線程編程 支持多線程編程是Java語言的又一大特色。多線程是相對(duì)于進(jìn)程或單線程而言的,它具有并發(fā)性、執(zhí)行效率高的特點(diǎn)。1 多線程編程概述2 線程的創(chuàng)建3 線程的優(yōu)先級(jí)4 線程同步5 線程間通信6 線程的控制1 1 多線程編程概述多線程編程概述 本節(jié)介紹多線程編程的基礎(chǔ)知識(shí),包括多線程的基本概念、Java的線程模型(線程優(yōu)先級(jí)、同步性、消息傳遞)等方面的內(nèi)容。 1.1 1.1 什么是多線程什么是多線程1.2 Java1.2 Java線程模型線程模型1.1 1.1 什么是多線程什么是多線程 同 其 他 大 多 數(shù) 編 程 語 言 不 同 , J a v a 內(nèi) 置 支 持

2、多 線 程 編 程(multithreaded programming)。多線程程序包含兩條或兩條以上并發(fā)運(yùn)行的部分,把程序中每個(gè)這樣的部分都叫作一個(gè)線程(thread)。每個(gè)線程都有獨(dú)立的執(zhí)行路徑,因此多線程是多任務(wù)處理的一種特殊形式。 讀者可能知道多任務(wù)處理,它實(shí)際上被所有的現(xiàn)代操作系統(tǒng)所支持。然而,多任務(wù)處理有兩種截然不同的類型:基于進(jìn)程的和基于線程的。搞清楚兩者的區(qū)別是很重要的。對(duì)大多數(shù)讀者來說,基于進(jìn)程的多任務(wù)處理是更熟悉的形式。進(jìn)程(process)本質(zhì)上是一個(gè)執(zhí)行的程序。因此基于進(jìn)程的多任務(wù)處理的特點(diǎn)是允許你的計(jì)算機(jī)同時(shí)運(yùn)行兩個(gè)或更多的程序。舉例來說,基于進(jìn)程的多任務(wù)處理使你在運(yùn)

3、用文本編輯器的時(shí)候可以同時(shí)運(yùn)行Java編譯器。在基于進(jìn)程的多任務(wù)處理中,程序是調(diào)度程序所分派的最小代碼單位。 而在基于線程(thread-based)的多任務(wù)處理環(huán)境中,線程是最小的執(zhí)行單位。這意味著一個(gè)程序可以同時(shí)執(zhí)行兩個(gè)或者多個(gè)任務(wù)的功能。例如,一個(gè)文本編輯器可以在打印的同時(shí)格式化文本。所以,多進(jìn)程程序處理“大圖片”,而多線程程序處理細(xì)節(jié)問題。1.2 Java1.2 Java線程模型線程模型 Java運(yùn)行系統(tǒng)在很多方面依賴于線程,所有的類庫設(shè)計(jì)都考慮到多線程。實(shí)際上,Java使用線程來使整個(gè)環(huán)境異步。這有利于通過防止CPU循環(huán)的浪費(fèi)來減少無效部分。 為更好地理解多線程環(huán)境的優(yōu)勢(shì),我們可以將

4、它與它的對(duì)照物相比較。單線程系統(tǒng)的處理途徑是使用一種叫作輪詢的事件循環(huán)方法。在該模型中,單線程控制在一無限循環(huán)中運(yùn)行,輪詢一個(gè)事件序列來決定下一步做什么。一旦輪詢裝置返回信號(hào)表明已準(zhǔn)備好讀取網(wǎng)絡(luò)文件,事件循環(huán)調(diào)度控制管理到適當(dāng)?shù)氖录幚沓绦?。直到事件處理程序返回,系統(tǒng)中沒有其他事件發(fā)生。這就浪費(fèi)了CPU時(shí)間。這導(dǎo)致了程序的一部分獨(dú)占了系統(tǒng),阻止了其他事件的執(zhí)行??偟膩碚f,單線程環(huán)境,當(dāng)一個(gè)線程因?yàn)榈却Y源時(shí)阻塞(block,掛起執(zhí)行),整個(gè)程序停止運(yùn)行。 Java多線程的優(yōu)點(diǎn)就在于取消了主循環(huán)/輪詢機(jī)制。一個(gè)線程可以暫停而不影響程序的其他部分。例如,當(dāng)一個(gè)線程從網(wǎng)絡(luò)讀取數(shù)據(jù)或等待用戶輸入時(shí)產(chǎn)生

5、的空閑時(shí)間可以被利用到其他地方。多線程允許活的循環(huán)在每一幀間隙中沉睡一秒而不暫停整個(gè)系統(tǒng)。在Java程序中出現(xiàn)線程阻塞,僅有一個(gè)線程暫停,其他線程繼續(xù)運(yùn)行。 線程存在多種狀態(tài)。線程可以正在運(yùn)行(running),只要獲得了CPU時(shí)間它就可以運(yùn)行;運(yùn)行的線程可以被掛起(suspend),并臨時(shí)中斷它的執(zhí)行;一個(gè)掛起的線程可以被恢復(fù)(resume),允許它從停止的地方繼續(xù)運(yùn)行;一個(gè)線程可以在等待資源時(shí)被阻塞(block);在任何時(shí)候,線程可以被終止(terminate),這將立即中斷運(yùn)行。一旦終止,線程不能被恢復(fù)。線程的各狀態(tài)間關(guān)系見圖所示與與JavaJava線程相關(guān)的幾個(gè)概念線程相關(guān)的幾個(gè)概念

6、Java給每個(gè)線程安排優(yōu)先級(jí)以決定與其他線程比較時(shí)該如何對(duì)待該線程。線程優(yōu)先級(jí)是詳細(xì)說明線程間優(yōu)先關(guān)系的整數(shù)。作為絕對(duì)值,優(yōu)先級(jí)是毫無意義的;當(dāng)只有一個(gè)線程時(shí),優(yōu)先級(jí)高的線程并不比優(yōu)先級(jí)低的線程運(yùn)行的快。相反,線程的優(yōu)先級(jí)是用來決定何時(shí)從一個(gè)運(yùn)行的線程切換到另一個(gè)。這叫“上下文轉(zhuǎn)換”(context switch)。決定上下文轉(zhuǎn)換發(fā)生的規(guī)則很簡(jiǎn)單: l線程可以自動(dòng)放棄控制。在I/O未決定的情況下,睡眠或阻塞由明確的讓步來完成。在這種假定下,所有其他的線程被檢測(cè),準(zhǔn)備運(yùn)行的最高優(yōu)先級(jí)線程被授予CPU。 l線程可以被高優(yōu)先級(jí)的線程搶占。在這種情況下,低優(yōu)先級(jí)線程不主動(dòng)放棄,處理器只是被先占無論它正

7、在干什么處理器被高優(yōu)先級(jí)的線程占據(jù)?;旧?,一旦高優(yōu)先級(jí)線程要運(yùn)行,它就執(zhí)行。這叫做有優(yōu)先級(jí)的多任務(wù)處理。 當(dāng)兩個(gè)相同優(yōu)先級(jí)的線程競(jìng)爭(zhēng)CPU周期時(shí),情形有一點(diǎn)復(fù)雜。對(duì)于Windows這樣的操作系統(tǒng),等優(yōu)先級(jí)的線程是在循環(huán)模式下自動(dòng)劃分時(shí)間的。1 1線程優(yōu)先級(jí)線程優(yōu)先級(jí)2 2同步性同步性 由于多線程在程序中引入了一個(gè)異步行為,故在需要的時(shí)候必須有加強(qiáng)同步性的方法。舉例來說,如果你希望兩個(gè)線程相互通信并共享一個(gè)復(fù)雜的數(shù)據(jù)結(jié)構(gòu),例如鏈表序列,就需要某些方法來確保它們沒有相互沖突。也就是說,你必須防止一個(gè)線程寫入數(shù)據(jù)而另一個(gè)線程正在讀取鏈表中的數(shù)據(jù)。為此,Java在進(jìn)程間同步性的老模式基礎(chǔ)上實(shí)行了另外

8、的一種方法:管程(monitor)。管程是一種由C.A.R.Hoare首先定義的控制機(jī)制。你可以把管程想象成一個(gè)僅控制一個(gè)線程的小盒子。一旦線程進(jìn)入管程,所有線程必須等待直到該線程退出了管程。用這種方法,管程可以用來防止共享的資源被多個(gè)線程操縱。 很多多線程系統(tǒng)將管程作為程序必須明確的引用和操作的對(duì)象。但Java提供一個(gè)清晰的解決方案,不提供“Monitor”類;相反,每個(gè)對(duì)象都擁有自己的隱式管程,當(dāng)對(duì)象的同步方法被調(diào)用時(shí)管程自動(dòng)載入。一旦一個(gè)線程包含在一個(gè)同步方法中,沒有其他線程可以調(diào)用相同對(duì)象的同步方法。這就使你可以編寫非常清晰和簡(jiǎn)潔的多線程代碼,因?yàn)橥街С质钦Z言內(nèi)置的。 3 3消息傳遞

9、消息傳遞 當(dāng)把程序分成若干線程后,就要定義各線程之間的聯(lián)系。用大多數(shù)其他語言規(guī)劃時(shí)必須依賴于操作系統(tǒng)來確立線程間通信,這樣當(dāng)然要增加花費(fèi)。然而,Java提供了多線程間談話清潔的、低成本的途徑通過調(diào)用所有對(duì)象都有的預(yù)先確定的方法。Java的消息傳遞系統(tǒng)允許一個(gè)線程進(jìn)入一個(gè)對(duì)象的一個(gè)同步方法,然后在那里等待,一直等到其他線程明確通知它出來。Return Java的多線程系統(tǒng)建立于Thread類、方法以及共伴接口Runnable基礎(chǔ)上。Thread類封裝了線程的執(zhí)行。既然不能直接引用運(yùn)行著的線程的狀態(tài),就要通過它的代理處理它。于是Thread 實(shí)例產(chǎn)生了。為創(chuàng)建一個(gè)新的線程,程序中必須擴(kuò)展Threa

10、d 或?qū)崿F(xiàn)Runnable接口。Thread類定義了好幾種方法來幫助管理線程。4 4ThreadThread類和類和RunnableRunnable接口接口2 2 線程的創(chuàng)建線程的創(chuàng)建 本節(jié)介紹在Java中如何創(chuàng)建線程。主要內(nèi)容包括主線程、多線程的創(chuàng)建、相關(guān)方法的使用等。 2.1 2.1 關(guān)于主線程關(guān)于主線程2.2 2.2 創(chuàng)建一個(gè)線程創(chuàng)建一個(gè)線程2.3 2.3 創(chuàng)建多線程創(chuàng)建多線程2.4 2.4 使用使用isAliveisAlive()()和和join()join()Return2.1 2.1 關(guān)于主線程關(guān)于主線程 當(dāng)Java程序啟動(dòng)時(shí),一個(gè)線程立刻運(yùn)行,該線程通常就叫做程序的主線程(mai

11、n thread),因?yàn)樗浅绦蜷_始時(shí)就執(zhí)行的。主線程的重要性主要體現(xiàn)在兩方面: l它是產(chǎn)生其他子線程的線程; l通常它必須最后完成執(zhí)行,因?yàn)樗鼒?zhí)行各種關(guān)閉動(dòng)作。 盡管主線程在程序啟動(dòng)時(shí)自動(dòng)創(chuàng)建,但它可以由一個(gè)Thread對(duì)象控制。為此,必須調(diào)用方法currentThread()獲得它的一個(gè)引用,currentThread()是Thread類的公有的靜態(tài)成員。它的一般形式如下 static Thread currentThread() 該方法返回一個(gè)調(diào)用它的線程的引用。一旦獲得主線程的引用,就可以像控制其他線程那樣控制主線程。 2.2 2.2 創(chuàng)建一個(gè)線程創(chuàng)建一個(gè)線程大多數(shù)情況,通過實(shí)例化一個(gè)

12、Thread對(duì)象來創(chuàng)建一個(gè)線程。Java定義了兩種方式: l實(shí)現(xiàn)Runnable 接口; l以繼承Thread類的方式。創(chuàng)建線程最簡(jiǎn)單的方法就是創(chuàng)建一個(gè)實(shí)現(xiàn)Runnable 接口的類,Runnable抽象了一個(gè)執(zhí)行代碼單元??梢酝ㄟ^實(shí)現(xiàn)Runnable接口的方法創(chuàng)建每一個(gè)對(duì)象的線程。為實(shí)現(xiàn) Runnable 接口,一個(gè)類僅需實(shí)現(xiàn)一個(gè)run()的簡(jiǎn)單方法,該方法聲明如下:public void run()在run()中,可以定義代碼來構(gòu)建新的線程。重要的是:run()方法能夠像主線程那樣調(diào)用其他方法,引用其他類,聲明變量。僅有的不同是:run()在程序中確立另一個(gè)并發(fā)的線程執(zhí)行入口。當(dāng)run()

13、返回時(shí),該線程結(jié)束。在已經(jīng)創(chuàng)建了實(shí)現(xiàn)Runnable接口的類以后,需要在類內(nèi)部實(shí)例化一個(gè)Thread類的對(duì)象。Thread 類定義了好幾種構(gòu)造函數(shù)。我們會(huì)用到的如下:Thread(Runnable threadOb, String threadName)在該構(gòu)造函數(shù)中,threadOb是一個(gè)實(shí)現(xiàn)Runnable接口類的實(shí)例。這定義了線程執(zhí)行的起點(diǎn),新線程的名稱由threadName定義。建立新的線程后,它并不運(yùn)行直到調(diào)用其start()方法,該方法在Thread 類中定義。從本質(zhì)上講,start()執(zhí)行的是一個(gè)對(duì)run()的調(diào)用。start()方法聲明如下:void start( )1 1實(shí)現(xiàn)

14、實(shí)現(xiàn)RunnableRunnable接口接口2 2擴(kuò)展擴(kuò)展ThreadThread 創(chuàng)建線程的另一個(gè)途徑是創(chuàng)建一個(gè)新類來擴(kuò)展Thread類,然后再創(chuàng)建該類的實(shí)例。當(dāng)一個(gè)類繼承Thread時(shí),它必須重載run()方法,這個(gè)run()方法是新線程的入口。同時(shí),它也必須調(diào)用start()方法去啟動(dòng)新線程執(zhí)行。 Return 到這里,讀者可能會(huì)奇怪為什么Java有兩種創(chuàng)建子線程的方法,哪一種更好呢。所有的問題都?xì)w于一點(diǎn)。Thread類定義了多種方法可以被派生類重載。對(duì)于所有的方法,唯一的必須被重載的是run()方法。這當(dāng)然是實(shí)現(xiàn)Runnable接口所需的同樣的方法。很多Java程序員認(rèn)為類僅在它們被加

15、強(qiáng)或修改時(shí)被擴(kuò)展。因此,如果你不重載Thread的其他方法,最好只實(shí)現(xiàn)Runnable 接口,這當(dāng)然由自己決定。在本章的其他部分,我們應(yīng)用實(shí)現(xiàn)Runnable接口的類來創(chuàng)建線程。 3 3選擇合適的方法選擇合適的方法2.4 2.4 使用使用isAliveisAlive()()和和join()join() 有時(shí)候存在這個(gè)問題:一個(gè)線程如何知道另一線程已經(jīng)結(jié)束?幸運(yùn)的是,Thread類提供了解決此問題的有效方法。 有兩種方法可以判定一個(gè)線程是否結(jié)束:第一,可以在線程中調(diào)用isAlive()。這種方法由Thread定義,它的一般形式如下final boolean isAlive() 如果所調(diào)用線程仍在

16、運(yùn)行,isAlive()方法返回true,如果不是則返回false。 但isAlive()很少用到,等待線程結(jié)束的更常用的方法是調(diào)用join(),描述如下final void join() throws InterruptedException 該方法等待所調(diào)用線程結(jié)束,該名字來自于要求線程等待直到指定線程參與的概念。join()的附加形式允許給等待指定線程結(jié)束定義一個(gè)最大時(shí)間。Return3 3 線程的優(yōu)先級(jí)線程的優(yōu)先級(jí) 線程優(yōu)先級(jí)被線程調(diào)度用來判定何時(shí)某個(gè)線程允許運(yùn)行。理論上,優(yōu)先級(jí)高的線程比優(yōu)先級(jí)低的線程獲得更多的CPU時(shí)間。實(shí)際上,線程獲得的CPU時(shí)間通常由包括優(yōu)先級(jí)在內(nèi)的多個(gè)因素決定

17、。一個(gè)優(yōu)先級(jí)高的線程自然比優(yōu)先級(jí)低的線程優(yōu)先。 理論上,等優(yōu)先級(jí)線程有同等的權(quán)利使用CPU,但你必須小心。需要記住的是,Java是被設(shè)計(jì)成能在很多環(huán)境下工作的。不同環(huán)境下實(shí)現(xiàn)多任務(wù)處理從本質(zhì)上來看是可能的。為安全起見,等優(yōu)先級(jí)線程有時(shí)候也受到控制。這保證了所有線程在無優(yōu)先級(jí)的操作系統(tǒng)下都有機(jī)會(huì)運(yùn)行。實(shí)際上,在無優(yōu)先級(jí)的環(huán)境下,多數(shù)線程仍然有機(jī)會(huì)運(yùn)行,因?yàn)楹芏嗑€程不可避免地會(huì)遭遇阻塞,例如等待輸入輸出。遇到這種情形,阻塞的線程掛起,其他線程運(yùn)行。但是如果你希望多線程執(zhí)行得順利的話,最好不要采用這種方法。同樣,有些類型的任務(wù)是占CPU的。對(duì)于這些支配CPU類型的線程,有時(shí)你希望能夠支配它們,以便使

18、其他線程可以運(yùn)行。 設(shè)置線程的優(yōu)先級(jí),用setPriority()方法,該方法也是Thread的成員。它的通常形式為 final void setPriority(int level)這里,level指定了對(duì)所調(diào)用的線程的新的優(yōu)先權(quán)的設(shè)置。Level的值必須在MIN_PRIORITY到MAX_PRIORITY范圍內(nèi)。通常,它們的值分別是1和10。要返回一個(gè)線程為默認(rèn)的優(yōu)先級(jí),指定NORM_PRIORITY,通常值為5。這些優(yōu)先級(jí)在Thread中都被定義為final型變量。 Return4 4 線程同步線程同步 當(dāng)兩個(gè)或兩個(gè)以上的線程需要共享資源,它們需要某種方法來確定資源在某一刻僅被一個(gè)線程占

19、用,達(dá)到此目的的過程叫做同步(synchronization)。Java為此提供了獨(dú)特的、很有效的支持機(jī)制。 4.1 4.1 使用同步方法使用同步方法4.2 4.2 同步語句同步語句Return4.1 4.1 使用同步方法使用同步方法 同步的關(guān)鍵是管程(也叫信號(hào)量,即semaphore)的概念。管程是一個(gè)互斥獨(dú)占鎖定的對(duì)象,或稱互斥體(mutex)。在給定的時(shí)間,僅有一個(gè)線程可以獲得管程。當(dāng)一個(gè)線程需要鎖定時(shí),它必須進(jìn)入管程。所有其他的試圖進(jìn)入已經(jīng)鎖定的管程的線程必須掛起直到第一個(gè)線程退出管程。這些其他的線程被稱為等待管程。 可以用兩種方法同步化代碼。通過調(diào)用sleep(),call()方法允

20、許執(zhí)行轉(zhuǎn)換到另一個(gè)線程。兩者都包括synchronized關(guān)鍵字的運(yùn)用。Return4.2 4.2 同步語句同步語句 盡管在創(chuàng)建的類的內(nèi)部創(chuàng)建同步方法是獲得同步的簡(jiǎn)單和有效的方法,但它并非在任何時(shí)候都有效。假設(shè)你想獲得不為多線程訪問設(shè)計(jì)的類對(duì)象的同步訪問,也就是該類沒有用到synchronized方法。而且,該類不是你自己,而是第三方創(chuàng)建的,就不能獲得它的源代碼。這樣,就不能在相關(guān)方法前加synchronized修飾符。怎樣才能使該類的一個(gè)對(duì)象同步化呢?解決的方法很簡(jiǎn)單:只需將對(duì)這個(gè)類定義的方法的調(diào)用放入一個(gè)synchronized塊內(nèi)就可以了。 下面是synchronized語句的一般形式

21、synchronized(object) / statements to be synchronized 其中,object是對(duì)同步對(duì)象的引用。如果你想要同步的只是一個(gè)語句,那么不需要花括號(hào)。一個(gè)同步塊確保對(duì)object成員方法的調(diào)用僅在當(dāng)前線程成功進(jìn)入object管程后發(fā)生。 5 5 線程間通信線程間通信 前面的例子無條件地阻塞了其他線程異步訪問某個(gè)方法。Java對(duì)象中隱式管程的應(yīng)用是很強(qiáng)大的,但是我們可以通過進(jìn)程間通信達(dá)到更微妙的境界,這在Java中是很簡(jiǎn)單的。 5.1 Java5.1 Java中的線程通訊中的線程通訊5.2 5.2 關(guān)于死鎖關(guān)于死鎖Return5.1 Java5.1 Ja

22、va中的線程通訊中的線程通訊 多線程通過把任務(wù)分成離散的和合乎邏輯的單元代替了事件循環(huán)程序。線程還有另外一個(gè)優(yōu)點(diǎn):它遠(yuǎn)離了輪詢。輪詢通常由重復(fù)監(jiān)測(cè)條件的循環(huán)實(shí)現(xiàn)。一旦條件成立,就要采取適當(dāng)?shù)男袆?dòng)。這浪費(fèi)了CPU時(shí)間。 為避免輪詢,Java包含了通過wait(),notify()和notifyAll()方法實(shí)現(xiàn)的一個(gè)進(jìn)程間通信機(jī)制。這些方法在對(duì)象中是用final方法實(shí)現(xiàn)的,所以所有的類都含有它們。這三個(gè)方法僅在synchronized方法中才能被調(diào)用。盡管這些方法從計(jì)算機(jī)科學(xué)遠(yuǎn)景方向上來說具有概念的高度先進(jìn)性,實(shí)際中用起來卻是很簡(jiǎn)單的。 wait()wait()告知被調(diào)用的線程放棄管程進(jìn)入睡眠直

23、到其他線程進(jìn)入相同管程并且調(diào)用notify()。 notify()notify()恢復(fù)相同對(duì)象中第一個(gè)調(diào)用wait()的線程。 notifyAllnotifyAll()()恢復(fù)相同對(duì)象中所有調(diào)用wait()的線程。這些方法在Object中被聲明,如下所示final void wait() throws InterruptedExceptionfinal void notify()final void notifyAll()wait()存在的另外的形式允許你定義等待時(shí)間。5.2 5.2 關(guān)于死鎖關(guān)于死鎖 需要避免的與多任務(wù)處理有關(guān)的特殊錯(cuò)誤類型是死鎖(deadlock)。死鎖發(fā)生在當(dāng)兩個(gè)線程對(duì)一

24、對(duì)同步對(duì)象有循環(huán)依賴關(guān)系時(shí)。例如,假定一個(gè)線程進(jìn)入了對(duì)象X的管程而另一個(gè)線程進(jìn)入了對(duì)象Y的管程。如果X的線程試圖調(diào)用Y的同步方法,它將像預(yù)料的一樣被鎖定。而Y的線程同樣希望調(diào)用X的一些同步方法,線程永遠(yuǎn)等待,因?yàn)闉榈竭_(dá)X,必須釋放自己的Y的鎖定以使第一個(gè)線程可以完成。死鎖是很難調(diào)試的錯(cuò)誤,這是因?yàn)椋旱谝?,通常它極少發(fā)生,只有到兩線程的時(shí)間段剛好符合時(shí)才能發(fā)生;第二,它可能包含多于兩個(gè)的線程和同步對(duì)象。也就是說,死鎖在比剛講述的例子有更多復(fù)雜的事件序列的時(shí)候可以發(fā)生。 為充分理解死鎖,觀察它的行為是很有用的。程序死鎖,需要按CTRL-C來結(jié)束程序。在PC機(jī)上按CTRL-BREAK(或在Solar

25、is下按CTRL-)可以看到全線程和管程緩沖堆。 6 6 線程的控制線程的控制 本節(jié)討論有關(guān)線程控制的問題,包括線程的掛起、恢復(fù)、終止等方面的問題。 6.1 6.1 掛起、恢復(fù)和終止線程掛起、恢復(fù)和終止線程6.2 Java 26.2 Java 2中的線程控制中的線程控制6.3 6.3 使用使用instanceofinstanceofReturn6.1 6.1 掛起、恢復(fù)和終止線程掛起、恢復(fù)和終止線程 有時(shí),線程的掛起是很有用的。例如,一個(gè)獨(dú)立的線程可以用來顯示當(dāng)日的時(shí)間。如果用戶不希望用時(shí)鐘,線程被掛起。在任何情形下,掛起線程是很簡(jiǎn)單的,一旦掛起,重新啟動(dòng)線程也是一件簡(jiǎn)單的事。 掛起、終止和恢

26、復(fù)線程機(jī)制在Java 2和早期版本中有所不同。盡管你運(yùn)用Java 2的途徑編寫代碼,仍需了解這些操作在早期Java環(huán)境下是如何完成的。例如,也許你需要更新或維護(hù)老的代碼,就需要了解為什么Java 2會(huì)有這樣的變化。因?yàn)檫@些原因,下面內(nèi)容說明了執(zhí)行線程控制的原始方法,接著是Java 2的方法。 先于Java2的版本(Java 1.1或更早版本),程序用Thread 定義的suspend() 和 resume() 來暫停和再啟動(dòng)線程。它們的形式如下。 final void suspend() final void resume() Thread類同樣定義了stop()來終止線程,其形式如下: vo

27、id stop() 一旦線程被終止,它不能被resume() 恢復(fù)繼續(xù)運(yùn)行。 6.2 Java 26.2 Java 2中的線程控制中的線程控制 在Java 2中不能使用suspend(),resume()和stop() 方法來控制線程線程必須被設(shè)計(jì)成使用run()方法定期檢查來判定線程是否應(yīng)該被掛起,恢復(fù)或終止它自己的執(zhí)行。有代表性的,這由建立一個(gè)指示線程狀態(tài)的標(biāo)志變量來完成。只要該標(biāo)志設(shè)為“running”,run()方法必須繼續(xù)讓線程執(zhí)行。如果標(biāo)志設(shè)為“suspend”,線程必須暫停。若設(shè)為“stop”,線程必須終止。當(dāng)然,編寫這樣的代碼有很多方法,但中心主題對(duì)所有的程序應(yīng)該是相同的。從O

28、bject繼承的wait()和notify()方法控制線程的執(zhí)行 NewTread類包含了用來控制線程執(zhí)行的布爾型的實(shí)例變量suspendFlag。它被構(gòu)造函數(shù)初始化為false。Run()方法包含一個(gè)監(jiān)測(cè)suspendFlag的同步聲明的塊。如果變量是true,wait()方法被調(diào)用以掛起線程。Mysuspend()方法設(shè)置suspendFlag為true。Myresume()方法設(shè)置suspendFlag為false并且調(diào)用notify()方法來喚起線程。最后,main()方法被修改以調(diào)用mysuspend()和myresume()方法。 6.3 6.3 使用使用instanceofins

29、tanceof 在運(yùn)行時(shí)間內(nèi)知道對(duì)象類型是很有用的。例如,你有一個(gè)執(zhí)行線程生成各種類型的對(duì)象,其他線程處理這些對(duì)象。這種情況下,讓處理線程在接受對(duì)象時(shí)知道每一個(gè)對(duì)象的類型是大有裨益的。另一種在運(yùn)行時(shí)間內(nèi)知道對(duì)象的類型是很有用的情形是強(qiáng)制類型轉(zhuǎn)換。Java中非法強(qiáng)制類型轉(zhuǎn)換導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。很多非法的強(qiáng)制類型轉(zhuǎn)換在編譯時(shí)發(fā)生。然而包括類層次結(jié)構(gòu)的強(qiáng)制類型轉(zhuǎn)換可能是僅能在運(yùn)行時(shí)間里被察覺的非法強(qiáng)制類型轉(zhuǎn)換。 例如,一個(gè)名為A的父類能生成兩個(gè)子類B和C。這樣,在強(qiáng)制B對(duì)象轉(zhuǎn)換為類型A或強(qiáng)制C對(duì)象轉(zhuǎn)換為類型A都是合法的,但強(qiáng)制B對(duì)象轉(zhuǎn)換為C對(duì)象(或相反)都是不合法的。因?yàn)轭愋虯的一個(gè)對(duì)象可以引用B或C。但是你怎么知道,在運(yùn)

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(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)論