




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、第5章 異常處理和多線程,5.1 異常與異常類 5.2 異常的處理 5.3 多線程,5.1 異常與異常類,異常(Exception)是程序執(zhí)行期間發(fā)生的錯(cuò)誤。在Java程序執(zhí)行期間,產(chǎn)生的異常通常有三種類型:一是Java虛擬機(jī)由于某些內(nèi)部錯(cuò)誤產(chǎn)生的異常,這類異常不在用戶程序的控制之內(nèi),也不需要用戶處理這類異常;二是標(biāo)準(zhǔn)異常,這類異常通常是由程序代碼中的錯(cuò)誤產(chǎn)生的,例如被0除、數(shù)組下標(biāo)越界等,這是需要用戶程序處理的異常;三是根據(jù)需要在用戶程序中自定義的一些異常。,返回,下一頁(yè),5.1 異常與異常類,5.1.1 異常處理機(jī)制 在Java語(yǔ)言中,所有的異常都是用類表示的。當(dāng)程序發(fā)生異常時(shí),會(huì)生成某個(gè)
2、異常類的對(duì)象。Throwable是java.lang包中一個(gè)專門用來處理異常的類,它有兩個(gè)直接子類:Error和Exception。 Error類型的異常與Java虛擬機(jī)本身發(fā)生的錯(cuò)誤有關(guān),用戶程序不需要處理這類異常。程序產(chǎn)生的錯(cuò)誤由Exception的子類表示,用戶程序應(yīng)該處理這類異常。 Exception中定義了許多異常類,每個(gè)異常類代表了一種執(zhí)行錯(cuò)誤,類中包含了對(duì)應(yīng)于這種運(yùn)行錯(cuò)誤的信息和處理錯(cuò)誤的方法等內(nèi)容。當(dāng)程序執(zhí)行期間發(fā)生一個(gè)可識(shí)別的執(zhí)行錯(cuò)誤時(shí),如果該錯(cuò)誤有一個(gè)異常類與之相對(duì)應(yīng),那么系統(tǒng)都會(huì)產(chǎn)生一個(gè)相應(yīng)的該異常類的對(duì)象。一旦一個(gè)異常對(duì)象產(chǎn)生了,系統(tǒng)中就一定有相應(yīng)的機(jī)制來處理它,從而保
3、證用戶程序在整個(gè)執(zhí)行期間不會(huì)產(chǎn)生死機(jī)、死循環(huán)等異常情況。Java語(yǔ)言采用這種異常處理機(jī)制來保證用戶程序執(zhí)行的安全性。,下一頁(yè),上一頁(yè),返回,5.1 異常與異常類,5.1.2 異常類的繼承結(jié)構(gòu) Java語(yǔ)言的Exception類的繼承結(jié)構(gòu)如圖5-1所示。 Exception類的每一個(gè)子類代表一種異常,這些異常表示程序執(zhí)行期間各種常見的錯(cuò)誤類型,它是Java系統(tǒng)事先定義好的并包含在Java語(yǔ)言類庫(kù)中,稱為系統(tǒng)定義的執(zhí)行異常。表5-1對(duì)一些常見的系統(tǒng)定義的執(zhí)行異常做了簡(jiǎn)要說明。 Exception類的兩個(gè)構(gòu)造函數(shù)是: public Exception(); public Exception(Stri
4、ng s); 其中,第二個(gè)構(gòu)造函數(shù)可以接受字符串參數(shù)傳入的信息,這個(gè)信息是對(duì)異常對(duì)象所對(duì)應(yīng)的錯(cuò)誤的描述。,下一頁(yè),上一頁(yè),返回,圖5-1,返回,表5-1,返回,5.1 異常與異常類,Exception類也從父類Throwable那里繼承了一些方法,最常用的兩個(gè)方法是: public String toString(); public void printStackTrace(); 其中,第一個(gè)方法是返回描述當(dāng)前Exception類信息的字符串。第二個(gè)方法的主要功能是在屏幕上輸出異常信息,這個(gè)異常信息是由Java系統(tǒng)對(duì)用戶程序執(zhí)行過程中產(chǎn)生的異常方法進(jìn)行跟蹤時(shí)產(chǎn)生的,并由PrintStackTr
5、ace()方法輸出到標(biāo)準(zhǔn)出錯(cuò)輸出流,對(duì)于控制臺(tái)程序來說,這個(gè)輸出流就是屏幕。 Java程序在執(zhí)行期間如果引發(fā)了一個(gè)Java系統(tǒng)能夠識(shí)別的錯(cuò)誤,就會(huì)產(chǎn)生一個(gè)與該錯(cuò)誤相對(duì)應(yīng)的異常類對(duì)象,這個(gè)過程稱為拋出(throw)異常。所有Java系統(tǒng)定義的執(zhí)行異常都可以由系統(tǒng)自動(dòng)拋出。下面的例子用來測(cè)試在數(shù)組越界時(shí)出現(xiàn)的異常。,下一頁(yè),上一頁(yè),返回,5.1 異常與異常類,public class TestSystemException public static void main(String args) int num=new int3; for(int i=0;i4;i+) numi=i; System
6、.out.println( num+i+=+i); 程序的運(yùn)行結(jié)果如圖5-2所示。,下一頁(yè),上一頁(yè),返回,圖5-2,返回,5.1 異常與異常類,上例所示的程序在執(zhí)行期間,由于在進(jìn)行第四次for循環(huán)時(shí)存在著數(shù)組越界的錯(cuò)誤,所以將引發(fā)ArrayIndexOutOfBoundsException異常。這個(gè)異常是Java系統(tǒng)已經(jīng)定義好的一個(gè)異常類,所以Java系統(tǒng)遇到這個(gè)錯(cuò)誤就自動(dòng)終止程序的執(zhí)行,并新建立一個(gè)ArrayIndexOutOfBoundsException類的對(duì)象,也就是拋出了一個(gè)數(shù)組越界異常。,上一頁(yè),返回,5.2 異常的處理,當(dāng)程序在執(zhí)行期間發(fā)生異常時(shí),可以采取兩種方法對(duì)異常進(jìn)行處理。
7、一是由Java語(yǔ)言的異常處理機(jī)制來完成處理工作,但是采用這種處理方法時(shí)用戶預(yù)先無法得知程序是發(fā)生了何種異常,用戶無法對(duì)可能發(fā)生的異常做出適當(dāng)?shù)奶幚?;二是用戶使用Java系統(tǒng)提供的try-catch-finally組合語(yǔ)句處理可能的異常。這樣一方面可以允許用戶修正錯(cuò)誤,另一方面可以避免因程序引起的異常而終止程序的執(zhí)行。異常的處理通常由捕捉異常、程序流程的轉(zhuǎn)移和異常處理語(yǔ)句塊的定義3個(gè)執(zhí)行步驟組成。,下一頁(yè),返回,5.2 異常的處理,5.2.1 捕捉異常 當(dāng)程序拋出一個(gè)異常時(shí),程序中應(yīng)該有專門的語(yǔ)句來接收這個(gè)被拋出的異常對(duì)象,這個(gè)過程被稱為捕捉(catch)異常。當(dāng)一個(gè)異常類的對(duì)象被捕捉和接收后,
8、用戶程序的執(zhí)行流程就會(huì)發(fā)生轉(zhuǎn)移,Java系統(tǒng)中止當(dāng)前的程序流程而轉(zhuǎn)到專門用來處理異常的語(yǔ)句塊,或者直接終止當(dāng)前程序的執(zhí)行而返回到操作系統(tǒng)狀態(tài)。 在進(jìn)行程序設(shè)計(jì)時(shí),為了避免因程序引起的異常而終止程序的執(zhí)行,通常將監(jiān)視異常的程序代碼放在try語(yǔ)句塊中。當(dāng)程序代碼出現(xiàn)異常時(shí),這個(gè)try語(yǔ)句塊就啟動(dòng)Java系統(tǒng)的異常處理機(jī)制來拋出一個(gè)異常對(duì)象,然后這個(gè)異常對(duì)象將被緊接在try語(yǔ)句塊之后的catch語(yǔ)句塊捕獲。,下一頁(yè),上一頁(yè),返回,5.2 異常的處理,當(dāng)異常對(duì)象被拋出后,程序的執(zhí)行流程將按非正常、非線性的方式執(zhí)行。如果此時(shí)在程序中沒有匹配的catch語(yǔ)句塊,那么程序?qū)⒈唤K止而返回到操作系統(tǒng)狀態(tài)。為了避
9、免發(fā)生這種情況,Java系統(tǒng)提供了finally語(yǔ)句塊來解決這個(gè)問題。具體做法是,將finally語(yǔ)句塊放在try與catch語(yǔ)句塊之后,也就是說,不管異常對(duì)象被拋出還是沒有被拋出,都將執(zhí)行finally語(yǔ)句塊。 try-catch-finally組合語(yǔ)句的一般語(yǔ)法格式如下: try / 可能發(fā)生異常的語(yǔ)句塊 catch(異常類名 異常形式參數(shù)名) /處理異常的語(yǔ)句塊 finally /無論是否發(fā)生異常都要被執(zhí)行的語(yǔ)句塊 ,下一頁(yè),上一頁(yè),返回,5.2 異常的處理,(1)catch語(yǔ)句括號(hào)內(nèi)的異常類名指明了用戶程序想要捕捉的異常類型。當(dāng)程序執(zhí)行期間發(fā)生異常時(shí),catch語(yǔ)句塊會(huì)捕捉這個(gè)異常,并
10、以語(yǔ)句塊內(nèi)的程序代碼來處理異常。 (2)無論try語(yǔ)句塊內(nèi)的程序代碼是否發(fā)生異常,finally語(yǔ)句塊內(nèi)的程序代碼都會(huì)被執(zhí)行。需要說明的是,finally語(yǔ)句塊是可以省略的,而try語(yǔ)句塊必須與catch或finally語(yǔ)句塊之一配對(duì)使用。也就是說,try語(yǔ)句塊單獨(dú)使用是沒有意義的。/TestCatchException.java public class TestCatchException public static void main(String args) int num=new int2;,下一頁(yè),上一頁(yè),返回,5.2 異常的處理,try for(int i=0;i3;i+) nu
11、mi=i; System.out.println( num+i+=+i); catch(ArrayIndexOutOfBoundsException e) System.out.println(數(shù)組下標(biāo)越界引起的異常); e.printStackTrace(); finally System.out.println(程序執(zhí)行期間發(fā)生了異常!); 程序的運(yùn)行結(jié)果如圖5-3所示。,下一頁(yè),上一頁(yè),返回,圖5-3,返回,5.2 異常的處理,5.2.2 異常的拋出 上小節(jié)介紹的是如何使用異常處理機(jī)制來捕捉系統(tǒng)已經(jīng)定義好的異常類的對(duì)象,這些異常發(fā)生時(shí)會(huì)由Java系統(tǒng)自動(dòng)地拋出。同時(shí),Java系統(tǒng)還允許用
12、戶在程序中自己定義異常類,并且用throw語(yǔ)句拋出,這就為Java程序的設(shè)計(jì)帶來了更大的靈活性。 1. 用戶自定義的異常類 用戶自定義的異常類一般通過繼承Exception類的形式來實(shí)現(xiàn)。下面是一個(gè)自定義異常類的程序段: public class MyException extends Exception /類體 ,下一頁(yè),上一頁(yè),返回,5.2 異常的處理,對(duì)于自定義的異常類,Java系統(tǒng)是不會(huì)自動(dòng)為用戶拋出屬于該類的對(duì)象的,用戶必須在程序中使用關(guān)鍵字throw來自行拋出異常對(duì)象。 使用關(guān)鍵字throw的一般語(yǔ)法格式如下: throw異常類對(duì)象; 這里的“異常類對(duì)象”既可以是用戶自定義的異常類
13、,也可以是Java系統(tǒng)已經(jīng)定義好的異常類。例如: TestThrowException.java class MyException extends Exception /自定義的異常類 String NewExceptionObject;,下一頁(yè),上一頁(yè),返回,5.2 異常的處理,public MyException()/構(gòu)造函數(shù) this.NewExceptionObject=; public MyException(String s)/構(gòu)造函數(shù) this.NewExceptionObject=s; String ShowExceptionInfo()/返回接收到的異常信息 return
14、this.NewExceptionObject; ,下一頁(yè),上一頁(yè),返回,5.2 異常的處理,public class TestThrowException public static void main(String args) try throw new MyException(這是一個(gè)自行拋出的異常! ); /拋出異常 catch(MyException e) System.out.println(MyException 類:); System.out.println(已經(jīng)捕捉到拋出的異常對(duì)象!); System.out.println(異常信息:+e.ShowExceptionInfo
15、() ); 程序的運(yùn)行結(jié)果如圖5-4所示。,下一頁(yè),上一頁(yè),返回,圖5-4,返回,5.2 異常的處理,說明: (1)在程序中自定義了一個(gè)新的異常類MyException,該類自Exception類繼承而得,并定義了兩個(gè)構(gòu)造函數(shù)和一個(gè)用來顯示接收到的異常參數(shù)“這是一個(gè)自行拋出的異常!”的方法ShowExceptionInfo()。 (2)在主類TestThrowException的定義中,try語(yǔ)句塊使用關(guān)鍵字throw將屬于MyException類的對(duì)象拋出。由于拋出的異常對(duì)象類型與catch語(yǔ)句括號(hào)中的異常類MyException相匹配,所以catch語(yǔ)句塊將捕捉這個(gè)異常對(duì)象,并將調(diào)用MyE
16、xception類中的方法ShowExceptionInfo(),將接收到的異常信息顯示在屏幕上。 (3)該程序省略了finally語(yǔ)句塊。,下一頁(yè),上一頁(yè),返回,5.2 異常的處理,2. 指定方法拋出的異常 如果一個(gè)方法不能處理它自己所引發(fā)的異常,那么異常處理的工作就需要由調(diào)用者來完成。在這種情況下,應(yīng)該在方法的定義中使用關(guān)鍵字throws來指明該方法可能引發(fā)的所有異常,讓調(diào)用者來處理這個(gè)異常。 包含throws子句的方法定義的一般語(yǔ)法格式如下: 修飾符 返回值類型 方法名(形式參數(shù)列表) throws 異常類 1,異常類 2, $ /方法體 /TestThrowsException.jav
17、a class MyException extends Exception String NewExceptionObject;,下一頁(yè),上一頁(yè),返回,5.2 異常的處理,public MyException() this.NewExceptionObject=; public MyException(String s) this.NewExceptionObject=s; String ShowExceptionInfo() return this.NewExceptionObject; public class TestThrowsException public static void
18、main(String args) try Test(); ,下一頁(yè),上一頁(yè),返回,5.2 異常的處理,catch(MyException e) System.out.println(MyException 類:); System.out.println(已經(jīng)捕捉到拋出的異常對(duì)象!); System.out.println(異常信息:+e.ShowExceptionInfo(); static void Test() throws MyException throw new MyException(方法自身產(chǎn)生的異常將由調(diào)用者處理! ); 程序的運(yùn)行結(jié)果如圖5-5所示。,下一頁(yè),上一頁(yè),返回,
19、圖5-5,返回,5.2 異常的處理,說明: (1)第112句中有關(guān)MyException類的定義與前面的例子完全一樣。 (2)在main()方法中,第16句調(diào)用Test()方法,而Test()方法是通過throw語(yǔ)句(第25句)產(chǎn)生一個(gè)MyException類的異常,但是Test()方法本身并不能處理所引發(fā)的異常。 (3)由于拋出的異常對(duì)象類型與第18句的catch語(yǔ)句括號(hào)中的異常類MyException相匹配,所以catch語(yǔ)句塊將捕捉這個(gè)異常對(duì)象,并將調(diào)用MyException類中的方法ShowExceptionInfo(),將接收到的異常信息輸出顯示在屏幕上。,上一頁(yè),返回,5.3 多線
20、程,5.3.1 線程與多線程 1. 線程 線程是存在于程序中的一個(gè)單獨(dú)的順序執(zhí)行流程。 所有的編程人員都很熟悉編寫順序執(zhí)行的程序,比如顯示“Hello World!”、對(duì)數(shù)據(jù)進(jìn)行簡(jiǎn)單排序、求方程的根等。這些程序有一個(gè)共同的特點(diǎn):每個(gè)程序只有一個(gè)起始點(diǎn)、一個(gè)執(zhí)行序列和一個(gè)結(jié)尾,在程序運(yùn)行的某一特定時(shí)刻只有一個(gè)執(zhí)行點(diǎn)。 對(duì)于一個(gè)線程來說,它很類似于一個(gè)順序執(zhí)行的程序,即一個(gè)單獨(dú)的線程也只有一個(gè)起始點(diǎn)、一個(gè)執(zhí)行序列和一個(gè)結(jié)尾,在線程運(yùn)行的某一特定時(shí)刻也只有一個(gè)執(zhí)行點(diǎn)。但是,一個(gè)線程只是一個(gè)程序的一部分,它本身并不能構(gòu)成一個(gè)完整的程序,換言之,程序可以獨(dú)立運(yùn)行,也可以擁有多個(gè)相互獨(dú)立的線程,而線程則不
21、然,它不能獨(dú)立運(yùn)行,也不能獨(dú)立存在,而必須“寄生”于一個(gè)程序之中。,下一頁(yè),返回,5.3 多線程,只包含一個(gè)線程的程序就是我們所熟悉的順序執(zhí)行程序,這時(shí)線程這一概念并未給我們帶來什么新意。而Java使用線程的神奇之處在于它使得一個(gè)程序可以使用多個(gè)線程,這些線程同時(shí)運(yùn)行,而每個(gè)線程則完成不同的功能。 多線程的一個(gè)最典型的應(yīng)用就是HotJava網(wǎng)絡(luò)瀏覽器。在HotJava網(wǎng)絡(luò)瀏覽器中,當(dāng)正在下載一個(gè)小應(yīng)用程序或一張圖的時(shí)候,用戶可以上下滾動(dòng)頁(yè)面,也可以使動(dòng)畫顯示與聲音同步等。引入多線程后,Java程序可以同時(shí)完成多項(xiàng)工作。 有些人稱線程為“輕量級(jí)的進(jìn)程”。一個(gè)線程和一個(gè)進(jìn)程都是一個(gè)單獨(dú)的順序執(zhí)行流
22、程,線程被認(rèn)為是“輕量級(jí)”的原因在于線程位于一個(gè)完整的程序上下文之中,它利用了程序分配的資源和程序的運(yùn)行環(huán)境。,下一頁(yè),上一頁(yè),返回,5.3 多線程,作為一個(gè)順序執(zhí)行流程,線程也必須擁有自己的運(yùn)行資源。例如:它必須擁有自己的執(zhí)行堆棧和程序計(jì)數(shù)器,線程的代碼只能在該上下文中運(yùn)行。因此,有人也把線程稱為“執(zhí)行上下文”。 2. 一個(gè)簡(jiǎn)單的多線程示例 下面是一個(gè)簡(jiǎn)單的線程示例。這個(gè)程序包含了SimpleThread和TwoThreadsTest兩個(gè)類。其中,SimpleThread類是從java.1ang類組定義的類Thread派生而來的。 class SimpleThread extends Thr
23、ead public SimpleThread(String str) /構(gòu)造過程, 設(shè)置線程的名稱 super(str); /構(gòu)造過程,通過引用父類的構(gòu)造過程來實(shí)現(xiàn) ,下一頁(yè),上一頁(yè),返回,5.3 多線程,public void run() /線程的核心過程 for(int i=0; i10; i+) System.out.println(i+ +getName(); try /Math.random()產(chǎn)生(0,1)上的均勻分布隨機(jī)數(shù) sleep(int)(Math.random()*1000); catch(InterruptedException e) System.out.print
24、ln(DONE!+ getName(); ,下一頁(yè),上一頁(yè),返回,5.3 多線程,SimpleThread類的實(shí)現(xiàn)包含了兩個(gè)過程。它的構(gòu)造過程通過調(diào)用其父類的構(gòu)造過程實(shí)現(xiàn),設(shè)置了線程的名稱。用戶可以用Thread類的過程getName()獲取這個(gè)名稱。過程run()是SimpleThread類的核心過程。過程run()也是所有線程的核心過程,它定義線程的行為。SimpleThread類的過程run()中包含一個(gè)次數(shù)為10次的循環(huán),每次循環(huán)輸出循環(huán)變量值和線程的名稱,并隨機(jī)休眠一段(1 s以內(nèi))時(shí)間;當(dāng)循環(huán)結(jié)束時(shí),過程run()顯示“DONE!”信息和線程名,這就是線程SimpleThread的
25、所有工作。 TwoThreadsTest類提供了main()過程,創(chuàng)建并啟動(dòng)了兩個(gè)SimpleThread線程:“Threadl”和“Thread2”,其代碼如下:,下一頁(yè),上一頁(yè),返回,5.3 多線程,class TwoThreadsTest public static void main(String args) new SimpleThread(Thread1).start(); /創(chuàng)建并啟動(dòng)線程 Thread1 new SimpleThread(Thread2).start(); /創(chuàng)建并啟動(dòng)線程 Thread2 這個(gè)程序每次的輸出結(jié)果是不一樣的,如圖5-6所顯示的是某一次輸出的結(jié)果。
26、,下一頁(yè),上一頁(yè),返回,圖5-6,返回,5.3 多線程,從上述輸出結(jié)果不難看出:兩個(gè)線程交錯(cuò)輸出,這是因?yàn)閮蓚€(gè)SimpleThread線程是同時(shí)運(yùn)行的,即它們的run()過程同時(shí)運(yùn)行,因而一起顯示各自的輸出。 這里主要是向用戶說明一個(gè)Java程序可以擁有多個(gè)線程,而這些線程是可以同時(shí)運(yùn)行的。而該示例中所使用的sleep(), start()等過程將在后面討論。,下一頁(yè),上一頁(yè),返回,5.3 多線程,5.3.2 創(chuàng)建線程 在Java語(yǔ)言中,可以用兩種方法創(chuàng)建線程。本節(jié)中將分別進(jìn)行介紹。 1. 創(chuàng)建線程的方法之一繼承Thread類 java.1ang.Thread是Java語(yǔ)言中用來表示進(jìn)程的類,
27、其中所定義的許多方法為完成線程的處理工作提供了比較完整的功能。如果將一個(gè)類定義為Thread的子類,那么這個(gè)類也就可以用來表示線程。 public class TwoThread public static void main(String args) ,下一頁(yè),上一頁(yè),返回,5.3 多線程,DelayPrintThread thread1,thread2; thread1 = new DelayPrintThread();/ 創(chuàng)建兩個(gè)線程對(duì)象 thread2 = new DelayPrintThread(); thread1.start();/開始執(zhí)行兩個(gè)線程 thread2.start()
28、; try Thread.sleep( 10000 );/主線程休眠10000 ms catch(InterruptedException e) System.out.println(thread has wrong); ,下一頁(yè),上一頁(yè),返回,5.3 多線程,class DelayPrintThread extends Thread private static int threadCount = 0; private int threadNumber = 0; private int delay; public DelayPrintThread() delay = (int)(Math.r
29、andom()*5000);/計(jì)算休眠時(shí)間 threadCount+;/線程計(jì)數(shù) threadNumber = threadCount;/線程號(hào) public void run() try sleep( delay );/子線程休眠一段時(shí)間 ,下一頁(yè),上一頁(yè),返回,5.3 多線程,catch ( InterruptedException e ) System.out.println( This is Thread# +threadNumber+ with a delay of +delay+. ); 運(yùn)行結(jié)果如圖5-7所示。 TwoThread類的main()方法中通過實(shí)例化兩個(gè)DelayPr
30、intThread不同的對(duì)象來創(chuàng)建兩個(gè)執(zhí)行線程。每個(gè)線程在它的start()方法被調(diào)用時(shí)開始執(zhí)行。因?yàn)槊總€(gè)DelayPrintThread表示一個(gè)獨(dú)立的線程,所以它們同時(shí)執(zhí)行。程序的一次輸出如屏幕圖(圖5-7)中所示。TwoThread程序的輸出在每次執(zhí)行時(shí)都將不一樣,這是因?yàn)閮蓚€(gè)線程在Java執(zhí)行系統(tǒng)中的執(zhí)行順序的不確定和這兩個(gè)線程中的每一個(gè)都將睡眠一個(gè)隨機(jī)產(chǎn)生的時(shí)間所造成的。,下一頁(yè),上一頁(yè),返回,圖5-7,返回,5.3 多線程,2. 創(chuàng)建線程的方法之二實(shí)現(xiàn)Runnable接口 Runnable是Java語(yǔ)言中用以實(shí)現(xiàn)線程的接口,從根本上講,任何實(shí)現(xiàn)線程功能的類都必須實(shí)現(xiàn)該接口。前面所用到
31、的Thread類實(shí)際上就是因?yàn)閷?shí)現(xiàn)了Runnable接口,所以它的子類才相應(yīng)具有線程功能。Runnable接口中只定義了一個(gè)方法,即run()方法,也就是線程體。 Thread的第二種構(gòu)造方法中包含有一個(gè)Runnable實(shí)例的參數(shù),這就是說,必須定義一個(gè)實(shí)現(xiàn)Runnable接口的類并產(chǎn)生一個(gè)該類的實(shí)例,對(duì)該實(shí)例的引用就是適合于這個(gè)構(gòu)造方法的參數(shù)。,下一頁(yè),上一頁(yè),返回,5.3 多線程,class TwoThread implements Runnable /實(shí)現(xiàn) Runnable 接口 TwoThread() /構(gòu)造方法 Thread Thread1 = Thread.currentThrea
32、d();/定義線程 1 Thread1.setName(The first main thread);/設(shè)置線程名 System.out.println(The running thread: + Thread1); Thread Thread2 = new Thread(this,the second thread); System.out.println(creat another thread); Thread2.start();/啟動(dòng)線程 2 ,下一頁(yè),上一頁(yè),返回,5.3 多線程,public void run() /重構(gòu) run 方法 try for ( int i = 0; i
33、5; i+ ) System.out.println(Sleep time for thread :+i); Thread.sleep(1000);/線程休眠 catch (InterruptedException e) System.out.println(thread has wrong); ,下一頁(yè),上一頁(yè),返回,5.3 多線程,public static void main(String args) new TwoThread();/創(chuàng)建兩個(gè)線程對(duì)象 運(yùn)行結(jié)果如圖5-8所示。,下一頁(yè),上一頁(yè),返回,圖5-8,返回,5.3 多線程,上例是通過繼承接口的方式來創(chuàng)建、啟動(dòng)線程的。該程序執(zhí)行結(jié)
34、果為每隔1000 ms有一次輸出顯示,共循環(huán)5次。在main線程1中使用newThread(this,the second thread)創(chuàng)建另一個(gè)線程對(duì)象,通過傳遞第一個(gè)參數(shù)來標(biāo)明新線程是調(diào)用this對(duì)象的run()方法,使線程2從run()方法開始執(zhí)行,即當(dāng)構(gòu)造線程類的一個(gè)新的實(shí)例時(shí),需要告訴它在新的線程里應(yīng)該執(zhí)行哪一段程序(run()方法)。 總之,線程由Thread對(duì)象的實(shí)例來引用。線程執(zhí)行的代碼來源于傳遞給Thread構(gòu)造方法的參數(shù)引用的類,這個(gè)類必須采用實(shí)現(xiàn)接口Runnable,線程操作的數(shù)據(jù)來源于傳遞給Thread構(gòu)造方法的Runnable實(shí)例。,下一頁(yè),上一頁(yè),返回,5.3 多
35、線程,3. 關(guān)于兩種創(chuàng)建線程方法的討論 既然兩種方法創(chuàng)建線程效果相同,那么使用哪一種創(chuàng)建線程的方法更好?如何決定選擇兩種方法中的哪一種呢?下面分別列出了每種方法的適用范圍。 (1)適用于采用實(shí)現(xiàn)Runnable接口的情況。由于Java語(yǔ)言只允許單繼承,如果一個(gè)類已經(jīng)繼承了Thread,就不能再繼承其他類,這時(shí)就被迫采用實(shí)現(xiàn)Runnable接口的方法。比如,對(duì)于Applet程序,由于必須繼承java.applet.Applet,因此就只能采取這種實(shí)現(xiàn)接口的方法。再有,由于上面的原因而幾次被迫采用實(shí)現(xiàn)Runnable接口的方法,可能會(huì)出于保持程序風(fēng)格的一貫性而繼續(xù)使用這種方法。,下一頁(yè),上一頁(yè),返
36、回,5.3 多線程,(2)適用于采用繼承Thread方法的情況。當(dāng)一個(gè)run()方法置于Thread類的子類中時(shí),this實(shí)際上引用的是控制當(dāng)前運(yùn)行系統(tǒng)的Thread實(shí)例,所以,代碼不必寫得像下面這樣繁瑣: Thread.currentThread().suspend(); 而可簡(jiǎn)單地寫為: suspend(); 因?yàn)榇a稍微簡(jiǎn)潔一些,所以許多Java程序員愿意使用繼承Thread的方法。但是應(yīng)該知道,如果采取這種簡(jiǎn)單的繼承模式,在以后的繼承中可能會(huì)出現(xiàn)麻煩。,下一頁(yè),上一頁(yè),返回,5.3 多線程,5.3.3 線程的啟動(dòng) 雖然一個(gè)線程已經(jīng)被創(chuàng)建,但它實(shí)際上并沒有立刻運(yùn)行。要使線程真正在Java
37、環(huán)境中運(yùn)行,必須通過方法start()來啟動(dòng),start()方法也在Thread類中。 例如,只要執(zhí)行“Thread1.start();”,此時(shí),線程中的虛擬CPU已經(jīng)就緒,所以也可以把這一過程想象為打開虛擬CPU的開關(guān)。,下一頁(yè),上一頁(yè),返回,5.3 多線程,5.3.4 線程的調(diào)度 雖然就緒后線程已經(jīng)可以運(yùn)行,但它并不意味著這個(gè)線程一定能夠立刻運(yùn)行。顯然,在一臺(tái)實(shí)際上只具有一個(gè)CPU的機(jī)器上,CPU在同一時(shí)間只能分配給一個(gè)線程做一件事。那么現(xiàn)在就必須考慮,當(dāng)有多于一個(gè)的線程工作時(shí),CPU是如何分配的。 在Java中,線程調(diào)度通常是搶占式,而不是時(shí)間片式。搶占式調(diào)度是指可能有多個(gè)線程準(zhǔn)備運(yùn)行,但只有一個(gè)在真正運(yùn)行。一個(gè)線程獲得執(zhí)行權(quán),這個(gè)線程將持續(xù)運(yùn)行下去,直到它運(yùn)行結(jié)束或因?yàn)槟撤N原因而阻塞,再或者有另一個(gè)高優(yōu)先級(jí)線程就緒。最后一種情況稱為低優(yōu)先級(jí)線程被高優(yōu)先級(jí)線程所搶占。,下一頁(yè),上一頁(yè),返回,5.3 多線程,一個(gè)線程被阻塞的原因是多種多樣的,可能是因?yàn)閳?zhí)行了Thread.sleep()調(diào)用,故意讓它暫停一段時(shí)間;也可能是因?yàn)樾枰却粋€(gè)較慢的外部設(shè)備,例如磁盤或用戶。所有被阻塞的線程按次序排列,組成一個(gè)阻塞隊(duì)列。而所有就緒但沒有運(yùn)行的線程則根據(jù)其優(yōu)先級(jí)排入一個(gè)就緒隊(duì)列。當(dāng)CPU空閑時(shí),如果就緒隊(duì)列不空,就緒隊(duì)列中第一個(gè)具有最高優(yōu)先級(jí)的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝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ù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 西藏取水收費(fèi)管理辦法
- 異地辦公團(tuán)隊(duì)管理辦法
- 移動(dòng)推車定置管理辦法
- 萊蕪瓷器修復(fù)培訓(xùn)課件
- 高三上期末數(shù)學(xué)試卷
- 高考模擬感人數(shù)學(xué)試卷
- 定西市歷年中考數(shù)學(xué)試卷
- 德陽(yáng)市期末高二數(shù)學(xué)試卷
- 2025年03月浙江紹興嵊州市婦幼保健院第一次招聘編外合同制人員12人筆試歷年專業(yè)考點(diǎn)(難、易錯(cuò)點(diǎn))附帶答案詳解
- 2025至2030打印機(jī)市場(chǎng)行業(yè)市場(chǎng)深度研究與戰(zhàn)略咨詢分析報(bào)告
- 公對(duì)公咨詢居間協(xié)議書范本
- 七年級(jí)下冊(cè)英語(yǔ)語(yǔ)法填空專項(xiàng)訓(xùn)練100題含答案5篇
- 租房合同可打印版
- 2024年xx中學(xué)學(xué)生校服選用采購(gòu)實(shí)施方案
- DL∕T 2622-2023 1000kV高壓并聯(lián)電抗器局部放電現(xiàn)場(chǎng)測(cè)量技術(shù)導(dǎo)則
- 農(nóng)活承攬合同
- JT-T-1270.3-2019公路橋梁梳齒板伸縮裝置第3部分:整體錨固式伸縮裝置
- 廣東省茂名市2023-2024學(xué)年八年級(jí)下學(xué)期期末數(shù)學(xué)試題
- 遼寧省沈陽(yáng)沈河區(qū)七校聯(lián)考2024屆物理八下期末考試試題及答案解析
- DZ∕T 0221-2006 崩塌、滑坡、泥石流監(jiān)測(cè)規(guī)范(正式版)
- 小學(xué)英語(yǔ)祈使句練習(xí)題
評(píng)論
0/150
提交評(píng)論