Java語言程序設(shè)計電子課件 第5章 多線程編程與異常處理_第1頁
Java語言程序設(shè)計電子課件 第5章 多線程編程與異常處理_第2頁
Java語言程序設(shè)計電子課件 第5章 多線程編程與異常處理_第3頁
Java語言程序設(shè)計電子課件 第5章 多線程編程與異常處理_第4頁
Java語言程序設(shè)計電子課件 第5章 多線程編程與異常處理_第5頁
已閱讀5頁,還剩36頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

JAVA語言程序設(shè)計5.1線程的概念5.2線程的生命周期5.3線程的創(chuàng)建5.4線程案例5.5異常的概念與分類5.6異常處理機制5.7異常處理案例5.8綜合案例本章小結(jié)第5章

多線程編程與異常處理教學(xué)目標(biāo):隨著計算機硬件的更新,多核計算機已經(jīng)逐漸成為主流產(chǎn)品。為了充分發(fā)揮多核的優(yōu)勢,多線程編程成為編程人員必須要掌握的編程方式。程序設(shè)計人員編寫程序總是希望能夠按照預(yù)期情況運行,得出一個正確的結(jié)果。但有時候程序會莫名中斷或運行結(jié)果錯誤,Java語言對于這種預(yù)想不到的情況采用異常機制來進行處理。本章主要介紹Java多線程并行程序的建立和運用,同時介紹了異常的概念和異常處理機制。教學(xué)重點:掌握Java中線程的概念。掌握線程的生命周期。掌握兩種創(chuàng)建線程的方法。掌握異常的概念和分類。掌握Java異常處理機制。第5章

多線程編程與異常處理5.1.1基本概念1.進程在操作系統(tǒng)中,我們熟悉進程的概念,進程是指可以與其他程序并發(fā)執(zhí)行程序的一次執(zhí)行過程,是系統(tǒng)進行資源分配和調(diào)度的獨立單位,有時也稱為活動或任務(wù)。即進程是運行中的程序,是程序的一次運行活動,具有動態(tài)性和并發(fā)性。2.線程為了使計算機操作系統(tǒng)具有更好的并發(fā)性,減少程序在并發(fā)執(zhí)行時所付出的時空開銷,在操作系統(tǒng)中引入了線程的概念。線程是進程中的一個實體,是被系統(tǒng)調(diào)度和分配的基本單元,每個程序至少包含一個線程,就是“主線程”。5.1線程的概念5.1.1基本概念線程自己擁有很少的資源,但是它與同屬一個進程的其他線程共享該進程的全部資源,從而改善了系統(tǒng)資源的利用率。利用線程編程的概念叫作“多線程編程”。圖5-1表示了線程和進程之間的區(qū)別。進程就是只擁有一個線程的進程,因為所有的任務(wù)都有這一個線程完成,也稱該進程為重量級進程。而擁有多個線程的進程因為將任務(wù)分給多個線程來執(zhí)行,每個線程承擔(dān)的工作量減小,也被成為輕量級進程。圖5-1進程與線程關(guān)系5.1線程的概念5.1.2多線程的優(yōu)點對于多線程機制而言,一個進程可以有多個線程,這些線程共享該進程資源,這些線程駐留在相同的地址空間,共享數(shù)據(jù)和文件。如果一個線程修改了一個數(shù)據(jù)項,其他線程可以了解和使用此結(jié)果數(shù)據(jù)。使用多線程編程有以下優(yōu)點:①程序的運行速度可能加快。②用于創(chuàng)建和撤銷線程的開銷比創(chuàng)建和撤銷進程的系統(tǒng)開銷要少得多。③CPU在線程之間切換的開銷遠比進程之間切換的開銷小。④線程機制也增加了通訊的有效性。線程間通訊是在同一進程的地址空間內(nèi),共享主存和文件,非常簡單,無需內(nèi)核參與。⑤線程在一些等待的任務(wù)實現(xiàn)上可以釋放一些珍貴的資源。如內(nèi)存占用、文件讀寫等。5.1線程的概念5.2.1線程的各種狀態(tài)一個線程在他的整個生存期中可能以集中不通的狀態(tài)存在,如圖5-2所示。盡管線程啟動后成為可運行的,但他不一定就立即運行。單CPU的計算機上同一時間只能執(zhí)行一個操作。因此完整的生命周期內(nèi)通常要經(jīng)歷新建、可運行、運行、阻塞、死亡等五種狀態(tài)。圖5-2線程的生命周期5.2線程的生命周期5.2.2線程的各種方法線程在生命周期的不同狀態(tài)進行轉(zhuǎn)換時,涉及到了許多方法,表5-1介紹了常用方法的作用。表5-1線程的常用方法作用5.2線程的生命周期5.2.3線程的優(yōu)先級別在Java中線程的優(yōu)先級是用數(shù)字來表示的,分為10個級別。表5-2列出了不同優(yōu)先級別的取值范圍,默認值和對應(yīng)的常量。表5-2線程的優(yōu)先級5.2線程的生命周期線程可看做有三部分構(gòu)成:虛擬CPU、代碼和數(shù)據(jù)。代碼可以被多個線程共享,獨立于數(shù)據(jù)。當(dāng)兩個線程執(zhí)行同一個類的實例代碼時,這兩個線程共享同樣的代碼。同樣,數(shù)據(jù)也可以被多個線程共享,獨立于代碼。在Java編程中,線程是通過Java的軟件包java.lang中定義的類Thread來實現(xiàn)的。

(1)Thread類本身只是線程的虛擬CPU;

(2)線程所執(zhí)行的功能是通過方法run()來完成的,方法run()稱為線程體;

(3)在一個線程被建立并初始化以后,Java的運行時系統(tǒng)就自動調(diào)用run()方法。用戶可以有兩種方法構(gòu)造自己的run()方法:

(1)一種方法是繼承Thread類,定義一個類,繼承Thread的線程類,重寫其中的run()方法;

(2)另一種實現(xiàn)Runnable接口,定義一個類,實現(xiàn)Runnable的接口。重寫其中的run()方法,

該類對象作為Thread類的參數(shù)。5.3線程的創(chuàng)建5.3.1繼承Thread類創(chuàng)建線程采用繼承Thread方法創(chuàng)建線程的優(yōu)點是:run()方法被包含在繼承Thread類的類中,有助于簡化程序代碼。Thread類的構(gòu)造方法最常用的兩種:

PublicThread():分配新的Thread對象

PublicThread(Runnabletarget):分配新的Thread對象。繼承Thread類的方法創(chuàng)建線程步驟如下:

(1)創(chuàng)建一個類,繼承Thread;

(2)重寫其中的方法run(),將用戶要實現(xiàn)的功能放入其中;

(3)在主方法中,創(chuàng)建線程,并用start()方法啟動線程;5.3線程的創(chuàng)建publicclassExample5_1extendsThread{ publicExample5_1(Stringname) {super(name);} publicvoidrun()//覆蓋run方法的線程體, {inti=1; Strings=getName(); while(i<=5) {System.out.println(s+""); i++; } System.out.println(s+"end!"); } publicstaticvoidmain(Stringargs[]) {Example5_1t1=newExample5_1("Thread1");//創(chuàng)建對象 Example5_1t2=newExample5_1("Thread2"); t1.start(); t2.start();//啟動執(zhí)行線程System.out.println("mainfind:activeCount="+activeCount());//獲取當(dāng)前活動的線程數(shù); } }【例5-1】采用繼承Thread類的方法,創(chuàng)建一個多線程的程序,通過循環(huán)打印兩個線程的名字,顯示線程執(zhí)行的順序。圖5-3運行結(jié)果5.3.2實現(xiàn)Runnable接口創(chuàng)建線程采用實現(xiàn)Runnable接口方法創(chuàng)建線程的優(yōu)點是:因為Java是單繼承,如果已經(jīng)擴展了某個父類,就只能用實現(xiàn)Runnable接口的方法。實現(xiàn)Runnable接口的方法創(chuàng)建線程步驟如下:

(1)創(chuàng)建一個類,實現(xiàn)Runnable接口;

(2)重寫其中的方法run(),將用戶要實現(xiàn)的功能放入其中;

(3)在主方法中,創(chuàng)建Thread類的實例,把目標(biāo)對象作為參數(shù)傳遞給這個線程實例,并用

start()方法啟動線程;5.3線程的創(chuàng)建publicclassExample5_2implementsRunnable{ Strings=null; publicExample5_2(Stringname){ s=name; } publicvoidrun()//覆蓋run方法的線程體, {inti=1; while(i<=5) {System.out.println(s+""); i++;} System.out.println(s+"end!"); } publicstaticvoidmain(Stringargs[]) {Example5_2Thread1=newExample5_2("Thread1"); Example5_2Thread2=newExample5_2("Thread2"); Threadt1=newThread(Thread1); Threadt2=newThread(Thread2); t1.start(); t2.start();//啟動執(zhí)行線程 }}【例5-2】采用實現(xiàn)Runnable接口的方法,創(chuàng)建一個多線程的程序,通過循環(huán)打印兩個線程的名字,顯示線程執(zhí)行的順序。1.任務(wù)要求用5個線程同時打印,輸出1-25之間的數(shù)字。2.目的練習(xí)多線程的使用,理解線程之間的執(zhí)行是沒有固定順序的。3.設(shè)計思路①利用繼承Thread類的方法創(chuàng)建類,在run()方法中完成任務(wù)。②25個數(shù)被5個線程分配,每個線程完成5個數(shù)的打印,循環(huán)5次。③創(chuàng)建線程實例,讓5個線程同時開始執(zhí)行。4.遇到問題①每個線程要從第幾個數(shù)開始打印怎么傳遞到任務(wù)中?②是否每次打印的結(jié)果都是一樣的?5.4線程的案例1)利用繼承Thread類的方法創(chuàng)建類,在run()方法中完成任務(wù)。2)25個數(shù)被5個線程分配,每個線程完成5個數(shù)的打印,循環(huán)5次。3)創(chuàng)建線程實例,讓5個線程同時開始執(zhí)行。1.設(shè)計思路1)每個線程要從第幾個數(shù)開始打印怎么傳遞到任務(wù)中?2)是否每次打印的結(jié)果都是一樣的?【解決問題1】每個線程應(yīng)有一個成員變量記錄開始打印的數(shù)字,因此在類中要設(shè)定成員變量m作為起始值,m的初始值由構(gòu)造方法傳入?!窘鉀Q問題2】多次執(zhí)行程序,查看結(jié)果順序,看是否每次打印都相同。2.遇到問題5.5.1異常的概念一個程序得出正確結(jié)果,需要編譯成功和運行無誤兩方面配合。程序發(fā)生的錯誤一般有兩種,一種錯誤是編譯錯誤,這可以在調(diào)試時解決;另一種錯誤在編譯時通過,但在運行時得不到正確結(jié)果。簡單的說,異常是指在硬件和操作系統(tǒng)正常時,程序在運行時遇到的非正常情況。這種在運行時出現(xiàn)的非正常情況可以通過異常處理來及時發(fā)現(xiàn)和解決。5.5異常的概念5.5.2Java中異常的分類Java語言用面向?qū)ο蟮姆绞絹硖幚懋惓?,異常以類的形式封裝,圖5-7給出了異常類的繼承關(guān)系。圖5-7異常類繼承關(guān)系圖5.5異常的概念publicclassExample5_3{publicstaticvoidmain(String[]args){inta,b,c;a=Integer.parseInt(args[0]);//獲得第一個輸入?yún)?shù),即被除數(shù)b=Integer.parseInt(args[1]);//獲得第二個輸入?yún)?shù),即除數(shù)c=a/b;System.out.println("兩數(shù)相除的結(jié)果是"+c);System.out.println("程序繼續(xù)運行到這里"+c);}}【例5-3】從鍵盤輸入兩個數(shù)進行相除運算,查看輸入的除數(shù)不為0和為0時程序的編譯及運行情況。importjava.io.*;publicclassExample5_4{publicstaticvoidmain(String[]args){ inta,b,c; a=Integer.parseInt(args[0]);//獲得第一個輸入的參數(shù),即被除數(shù) b=Integer.parseInt(args[1]);//獲得第二個輸入的參數(shù),即除數(shù) if(b==0){System.out.println("您輸入的除數(shù)為0,會導(dǎo)致程序運行錯誤,請重新輸入"); } else{ c=a/b; System.out.println("兩數(shù)相除的結(jié)果是"+c); System.out.println("程序繼續(xù)運行到這里"+c); } }}【例5-4】從鍵盤輸入兩個數(shù)進行相除,使用if-else語句避免除數(shù)為0時出現(xiàn)不友好界面。在上節(jié)的例子中,當(dāng)輸入的除數(shù)為0時,程序意外中斷,且出現(xiàn)的界面不友好。盡管我們也希望程序能夠按照正常順序運行至結(jié)束,得出正確結(jié)果,但程序在運行時不可避免的會遇到各種異常情況。健壯性是用來衡量程序在出現(xiàn)異常時候保持正常工作的能力。因此為了編寫健壯性較好的代碼,java語言提供了異常處理機制,可為其增加try……catch……finally語句。5.6異常處理機制5.6.1異常處理格式在Java語言中,使用try……catch……finally語句來捕獲異常,格式如下:try{可能出現(xiàn)異常的代碼塊;}catch(異常類型1異常對象1){異常處理語句塊1;}catch(異常類型2異常對象2){異常處理語句塊2;}……finally{finally塊;不論是否出現(xiàn)異常,必須執(zhí)行的代碼塊}5.6異常處理機制5.6.2異常處理步驟當(dāng)程序運行中發(fā)生異常時,java的異常處理機制將按照以下步驟處理:(1)當(dāng)try部分的某個語句發(fā)生異常后,產(chǎn)生異常對象,并終止當(dāng)前正在執(zhí)行的代碼,拋出異常對象。(2)異常對象從上到下與相應(yīng)的catch塊匹配,如果與其中一個異常類型相同,則執(zhí)行相應(yīng)catch塊中的異常處理語句,執(zhí)行finally語句塊;否則由java運行時系統(tǒng)的默認處理程序處理。(3)無論是否有異常產(chǎn)生,finally后的語句塊都被執(zhí)行。5.6異常處理機制5.6.3異常處理說明在以上的格式和處理步驟中,有幾點需要說明:①try塊中包含的是可能出現(xiàn)異常的代碼。②catch塊用于捕獲異常并處理異常。③finally塊中包含的是不論是否出現(xiàn)異常,都必須執(zhí)行的代碼。在編寫程序時,有些代碼是不管發(fā)生任何情況都必須執(zhí)行的,例如關(guān)閉打開的文件,關(guān)閉數(shù)據(jù)庫的連接等等。如果程序發(fā)生了異常,就必須中斷正常流程,轉(zhuǎn)去處理異常操作,這就使得上述情況的代碼沒有執(zhí)行的機會,從而造成混亂,影響程序的健壯性。所以Java語言提供了finally語句塊,無論是否發(fā)生異常,finally塊中的語句都被執(zhí)行,它為程序提供了統(tǒng)一的出口。5.6異常處理機制5.6.4編寫程序需要注意的問題①在使用try……catch……finally語句時,封裝每個語句塊的花括號不可以省略。②try塊中定義的變量,在catch塊和finally塊中不能訪問。③try代碼塊后面至少要有一個catch塊或者finally塊,如果catch和finally塊同時存在,finally塊要在catch塊后面。catch塊和try塊之間不能有其他代碼。5.6異常處理機制importjava.io.*;publicclassExample5_6{ publicstaticvoidmain(String[]args){ inta=8; try{ System.out.println(a); } finally{ System.out.println("執(zhí)行到這里了"); } }}【例5-6】該程序只有finally塊沒有catch塊,可以順利編譯通過,并得出正確結(jié)果。publicclassExample5_7{ publicstaticvoidmain(String[]args){ inta=8,b; try{ System.out.println(a); } b=10;//在try語句和catch語句之間加入其它語句會出現(xiàn)編譯錯誤 catch(Exceptione){ System.out.println(e.getMessage()); } finally{ System.out.println("執(zhí)行到這里了"); } }}【例5-7】在try塊和catch塊之間有其他的代碼,將出現(xiàn)編譯錯誤。importjava.io.*;publicclassExample5_8{ publicstaticvoidmain(String[]args){ try{ Filef=newFile("g:\\aa.txt"); f.createNewFile();//在g盤下創(chuàng)建aa.txt文件 } catch(NullPointerExceptione){//catch塊① System.out.println("發(fā)生了空指針異常"); }catch(Exceptione){//catch塊② System.out.println("發(fā)生了輸入輸出流異常"); } }}【例5-8】多個catch塊的依次匹配1.任務(wù)在控制臺輸入兩個數(shù),執(zhí)行兩數(shù)相除運算,將結(jié)果顯示在控制臺,如果相除運算產(chǎn)生異常,應(yīng)以友好界面在控制臺輸出產(chǎn)生異常的原因。無論是否發(fā)生異常,都要將輸入的兩個數(shù)顯示在控制臺上。2.設(shè)計思路①從控制臺依次輸入兩個整數(shù)存入變量a、b中②將a除以b的結(jié)果存入c中③輸出c的值④將可能發(fā)生異常的語句放入try語句塊中。⑤編寫catch塊捕獲除數(shù)為0異常。⑥finally語句塊輸出從控制臺輸入的兩個數(shù)的值。5.7異常處理案例3.遇到問題①如何從控制臺中輸入數(shù)據(jù)?②從控制臺輸入的數(shù)據(jù)是字符串類型還是整數(shù)數(shù)據(jù)類型?③在控制臺輸入的每一個數(shù)據(jù)采用何種方式輸入結(jié)束?④從控制臺輸入的兩個變量應(yīng)該定義在try塊的什么位置?⑤catch塊中的異常類型一定要和發(fā)生異常的類型精確匹配么?5.7異常處理案例【解決問題1】java.util包中的Scanner類可以接收從控制臺中輸入的數(shù)據(jù)。因此創(chuàng)建Scanner類的對象reader,用來獲取從控制臺輸入的數(shù)據(jù).Scannerreader=newScanner(System.in);【解決問題2】從控制臺輸入的數(shù)據(jù)是字符串類型,要將其轉(zhuǎn)換為基本數(shù)據(jù)類型,使用reader對象調(diào)用nextByte(),nextDouble(),nextFloat(),nextInt(),nexLong(),nextShort()等即可。本例中,使用reader.nextInt();【解決問題3】上述幾個方法執(zhí)行時都會造成堵塞,等待用戶在命令行輸入數(shù)據(jù)回車確認,所以只要輸入第一個數(shù)以后單擊回車鍵,即表明第一個數(shù)據(jù)讀取完畢。5.7異常處理案例【解決問題4】try語句塊中定義的變量屬于局部變量,該變量在finally塊中是不能被調(diào)用的,因此,保存從控制臺輸入數(shù)據(jù)的變量應(yīng)定義在try塊之外。inta,b;

try{

……

}【解決問題5】catch塊中的異常類型不用跟程序發(fā)生的異常精確匹配,子類對象可以與父類的catch相匹配。該題中拋出的一定是ArithmeticException異常,使用ArithmeticException或ArithmeticException的父類匹配均可。5.7異常處理案例5.8.1繪制垂直下落的小球在窗體中繪制一個小球,小球可以在窗體中垂直下落。5.8綜合案例(1)創(chuàng)建窗體對象frame,設(shè)置frame對象的相關(guān)屬性。(2)在窗體上繪制一個小球。(3)通過循環(huán)控制小球的縱坐標(biāo)在窗體高度范圍內(nèi)遞增。(4)引入

溫馨提示

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

評論

0/150

提交評論