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

下載本文檔

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

文檔簡(jiǎn)介

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

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

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

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

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

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

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

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

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

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

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

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

13、返回時(shí),該線(xiàn)程結(jié)束。在已經(jīng)創(chuàng)建了實(shí)現(xiàn)Runnable接口的類(lèi)以后,需要在類(lèi)內(nèi)部實(shí)例化一個(gè)Thread類(lèi)的對(duì)象。Thread 類(lèi)定義了好幾種構(gòu)造函數(shù)。我們會(huì)用到的如下:Thread(Runnable threadOb, String threadName)在該構(gòu)造函數(shù)中,threadOb是一個(gè)實(shí)現(xiàn)Runnable接口類(lèi)的實(shí)例。這定義了線(xiàn)程執(zhí)行的起點(diǎn),新線(xiàn)程的名稱(chēng)由threadName定義。建立新的線(xiàn)程后,它并不運(yùn)行直到調(diào)用其start()方法,該方法在Thread 類(lèi)中定義。從本質(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)建線(xiàn)程的另一個(gè)途徑是創(chuàng)建一個(gè)新類(lèi)來(lái)擴(kuò)展Thread類(lèi),然后再創(chuàng)建該類(lèi)的實(shí)例。當(dāng)一個(gè)類(lèi)繼承Thread時(shí),它必須重載run()方法,這個(gè)run()方法是新線(xiàn)程的入口。同時(shí),它也必須調(diào)用start()方法去啟動(dòng)新線(xiàn)程執(zhí)行。 Return 到這里,讀者可能會(huì)奇怪為什么Java有兩種創(chuàng)建子線(xiàn)程的方法,哪一種更好呢。所有的問(wèn)題都?xì)w于一點(diǎn)。Thread類(lèi)定義了多種方法可以被派生類(lèi)重載。對(duì)于所有的方法,唯一的必須被重載的是run()方法。這當(dāng)然是實(shí)現(xiàn)Runnable接口所需的同樣的方法。很多Java程序員認(rèn)為類(lèi)僅在它們被加

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

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

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

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

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

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

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

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

23、到其他線(xiàn)程進(jìn)入相同管程并且調(diào)用notify()。 notify()notify()恢復(fù)相同對(duì)象中第一個(gè)調(diào)用wait()的線(xiàn)程。 notifyAllnotifyAll()()恢復(fù)相同對(duì)象中所有調(diào)用wait()的線(xiàn)程。這些方法在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ò)誤類(lèi)型是死鎖(deadlock)。死鎖發(fā)生在當(dāng)兩個(gè)線(xiàn)程對(duì)一

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

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

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

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

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

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

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 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ì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論