JAVA編程 第13章_多線程.ppt_第1頁
JAVA編程 第13章_多線程.ppt_第2頁
JAVA編程 第13章_多線程.ppt_第3頁
JAVA編程 第13章_多線程.ppt_第4頁
JAVA編程 第13章_多線程.ppt_第5頁
已閱讀5頁,還剩24頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、第13章 多線程,多線程是Java中的并發(fā)機(jī)制,表示能夠在同一時(shí)間內(nèi)同時(shí)執(zhí)行多個(gè)操作。在日常生活中,邊上網(wǎng)邊聽歌就是一個(gè)多線程。隨著CPU進(jìn)入雙核,甚至多核時(shí)代,多線程的優(yōu)勢越來越明顯。Java本身就是一門支持多線程的語言,在Java中使用多線程是很方便的,同樣也是很高效的。通過本章的學(xué)習(xí),讀者應(yīng)該能夠完成如下幾個(gè)目標(biāo)。 了解什么是多線程。 熟練掌握如何定義和使用多線程。 了解多線程的生命周期。 掌握多線程的調(diào)用的幾個(gè)情況。 了解多線程的同步問題。,13.1 多線程簡介,多線程就好像日常生活中同時(shí)做幾件事一樣,例如早上起床,要燒水洗臉,在燒水時(shí)就可以刷牙,還可以邊刷牙邊看早間新聞,這樣就同時(shí)做

2、著燒水、刷牙、看電視三件事。多線程也是一樣的,在同一時(shí)刻有可能在執(zhí)行多個(gè)線程,這樣能夠更好地提高辦事效率。 在實(shí)際開發(fā)中也是在很多地方使用多線程的,例如在很多網(wǎng)站中,當(dāng)用戶注冊后,系統(tǒng)一方面會通知用戶已經(jīng)注冊成功,一方面向用戶在注冊時(shí)填寫的Email中發(fā)送郵件。這里就需要使用多線程,如果使用的是單線程,系統(tǒng)就會向用戶注冊的Email中發(fā)送郵件后才顯示用戶注冊成功,由于發(fā)送郵件可能需要很長的時(shí)間,從而影響整個(gè)注冊進(jìn)度。 在前面的學(xué)習(xí)中,雖然沒有使用多線程,但是同樣使用到了線程的知識。在每一個(gè)程序中的main方法就是一個(gè)線程,它一般被稱為主線程。在主線程中可以啟動(dòng)多個(gè)子線程來執(zhí)行。,13.2 定義

3、線程和創(chuàng)建線程對象,在上一小節(jié)中講解了什么是多線程,在本節(jié)中就來講解怎樣來定義線程和如何創(chuàng)建線程對象。定義線程有兩種方法,一種是繼承Thread類,一種是實(shí)現(xiàn)Runnable接口,這兩種方法是存在各自優(yōu)缺點(diǎn)的。和定義線程對應(yīng)的就是創(chuàng)建線程對象,也是有兩種方法。在本節(jié)中就來學(xué)習(xí)使用這兩種方法來定義線程,以及相對應(yīng)的創(chuàng)建線程對象。,13.2.1 繼承Thread類定義線程,定義一個(gè)線程可以通過繼承Thread類來實(shí)現(xiàn),這是一種相對簡單的定義線程的方法。在Thread類中具有一個(gè)run方法,在定義的線程中需要重寫這個(gè)方法。在重寫的run方法中,可以定義該線程所要執(zhí)行的語句。當(dāng)線程啟動(dòng)時(shí),run方法中

4、的程序就成為一條獨(dú)立的執(zhí)行線程。 【范例】示例代碼是一個(gè)通過繼承Thread類定義線程的程序。 示例代碼 01public class XianCheng1 extends Thread 02 03public void run() 04 05System.out.println(通過繼承Thread定義線程); 06 07,該程序是無法運(yùn)行的,因?yàn)闆]有main方法,也就是沒有啟動(dòng)線程的方法。在該程序中創(chuàng)建了一個(gè)線程類繼承于Thread類,并且在該類中重寫了run方法,在其中定義了該線程的功能是顯示一條語句。 注意:重寫的run方法也是可以作為一般的方法來調(diào)用的,但是這種調(diào)用并不是作為一個(gè)線程

5、出現(xiàn)的,它只是主線程中的一部分。同樣,run方法也是可以被重載的,但是重載后的run方法不作為一個(gè)線程,也是主線程的一部分。 講解完定義線程后,就可以來學(xué)習(xí)如何創(chuàng)建線程對象。通過繼承Thread類創(chuàng)建線程,是很容易創(chuàng)建線程對象的。在這種定義線程的方法中,創(chuàng)建線程對象和創(chuàng)建普通對象是一樣的。下面是創(chuàng)建示例代碼13-1中線程對象的代碼。 XianCheng1 xc=new XianCheng1(); 從創(chuàng)建線程對象的程序可以看出,創(chuàng)建線程對象的方法和創(chuàng)建普通對象的方法是一樣的。但是這只是對于使用繼承Thread類創(chuàng)建線程的方法來說的。,13.2.2 實(shí)現(xiàn)Runnable接口定義線程,定義線程除了通

6、過繼承Thread類來實(shí)現(xiàn),還可以通過實(shí)現(xiàn)Runnable接口來實(shí)現(xiàn)。在Runnable接口中具有一個(gè)抽象的run方法,在實(shí)現(xiàn)Runnable接口時(shí),需要實(shí)現(xiàn)該run方法。該run方法就會作為一個(gè)執(zhí)行線程的方法。 【范例】示例代碼是一個(gè)通過實(shí)現(xiàn)Runnable接口定義線程的程序。 示例代碼 01public class XianCheng2 implements Runnable 02 03public void run() 04 05System.out.println(通過實(shí)現(xiàn)Runnable接口定義線程); 06 07,1是通過繼承Thread類定義線程,2是通過實(shí)現(xiàn)Runnable接口

7、來定義線程。這兩種方法中都需要定義一個(gè)run方法,不管該方法是通過重寫父類方法,還是實(shí)現(xiàn)接口方法。run方法是一個(gè)線程的入口,是線程必須具有的。 在使用通過實(shí)現(xiàn)Runnable接口定義的線程中,要想創(chuàng)建線程對象就不是很容易做到的。因?yàn)橹苯觿?chuàng)建類對象,創(chuàng)建的并不是一個(gè)線程對象。要想創(chuàng)建線程對象,必須要借助Thread類。 Thread類具有4個(gè)構(gòu)造器,最常用的就是具有一個(gè)參數(shù),該參數(shù)是實(shí)現(xiàn)Runnable接口類對象的構(gòu)造器。創(chuàng)建線程對象的程序如下所示。 XianCheng2 xc=new XianCheng2(); Thread t=new Thread(xc); 在該程序中,首先創(chuàng)建了一個(gè)實(shí)現(xiàn)

8、Runnable接口的類對象,然后將該對象作為Thread類的參數(shù),從而創(chuàng)建了一個(gè)線程對象。創(chuàng)建的類對象是可以作為多個(gè)Thread類構(gòu)造器參數(shù)的,這樣就創(chuàng)建了多個(gè)線程。這一點(diǎn)將在以后的學(xué)習(xí)中多次使用。,13.3 運(yùn)行線程,在上一節(jié)中學(xué)習(xí)了如何定義線程,并且知道了如何創(chuàng)建線程對象。對這些都了解后就需要來學(xué)習(xí)如何運(yùn)行線程。在本節(jié)中分為兩個(gè)小節(jié)來講解,先來學(xué)習(xí)如何啟動(dòng)線程,然后講解如何運(yùn)行多個(gè)線程。,13.3.1 啟動(dòng)線程,有些讀者會認(rèn)為啟動(dòng)線程就是調(diào)用線程類中的run方法。例如示例代碼13-3中所演示的。 【范例】示例代碼是一個(gè)錯(cuò)誤的啟動(dòng)線程的程序。 示例代碼 01class MyRunnable

9、 implements Runnable 02 03/定義一個(gè)run線程方法 04public void run() 05 06System.out.println(這是一個(gè)錯(cuò)誤的啟動(dòng)線程的程序); 07 08 09public class XianCheng3 10 11public static void main(String args) 12 13MyRunnable mr=new MyRunnable(); 14mr.run();/調(diào)用run方法 15 16,從該程序可以看出,run方法是可以通過方法調(diào)用來執(zhí)行的,但是這并不代表創(chuàng)建了一個(gè)新線程。這是一個(gè)錯(cuò)誤的啟動(dòng)線程的方法。 如果想

10、正確地啟動(dòng)一個(gè)線程,需要調(diào)用線程對象的start方法,下面通過程序來演示如何正確的啟動(dòng)一個(gè)線程。,一個(gè)正確的啟動(dòng)線程的程序,01class MyRunnable implements Runnable 02 03/定義一個(gè)run線程方法 04public void run() 05 06System.out.println(這是一個(gè)正確的啟動(dòng)線程的程序); 07 08 09public class XianCheng4 10 11public static void main(String args) 12 13MyRunnable mr=new MyRunnable(); 14Thread

11、t=new Thread(mr); 15t. start ();/啟動(dòng)線程 16 17,【代碼解析】第一次看到該程序時(shí),讀者可能會感到有些奇怪,為什么調(diào)用的是start方法,而執(zhí)行的是run方法,這就是Java對多線程的設(shè)計(jì)。在調(diào)用start方法后,就啟動(dòng)了線程,該線程是和main方法并列執(zhí)行的線程。這樣該程序就變?yōu)橐粋€(gè)多線程程序。 注意:線程只能被啟動(dòng)一次,也就是只能調(diào)用一次start方法。當(dāng)多次啟動(dòng)線程,也就是多次調(diào)用start方法時(shí),就會發(fā)生異常。,13.3.2 同時(shí)運(yùn)行多個(gè)線程,學(xué)習(xí)了如何啟動(dòng)線程,接下來就來學(xué)習(xí)如何同時(shí)運(yùn)行多個(gè)線程。首先通過示例代碼來看一下如何同時(shí)運(yùn)行多個(gè)線程。 27

12、public static void main(String args) 28 29MyRunnable1 mr1=new MyRunnable1(); 30MyRunnable2 mr2=new MyRunnable2(); 31Thread t1=new Thread(mr1); 32Thread t2=new Thread(mr2); 33t1.start();/啟動(dòng)第一個(gè)線程 34t2.start();/啟動(dòng)第二個(gè)線程 35 36,【代碼解析】在示例代碼13-6中首先定義了兩個(gè)實(shí)現(xiàn)Runnable接口的類,在兩個(gè)類中都定義了run方法,顯示多個(gè)不同的符號。從運(yùn)行結(jié)果中可以看出,不同的符

13、號是交替顯示的。 在同時(shí)運(yùn)行多個(gè)線程時(shí),運(yùn)行結(jié)果不是唯一的,因?yàn)橛泻芏嗖淮_定的因素。首先先執(zhí)行哪一個(gè)線程就是不確定的,線程間交替也是不確定的。但是確定的是每一個(gè)線程都將啟動(dòng),每一個(gè)線程都執(zhí)行結(jié)束。,13.4 線程生命周期,線程是存在生命周期的。線程的生命周期分為五種不同的狀態(tài),分別是新建狀態(tài)、準(zhǔn)備狀態(tài)、運(yùn)行狀態(tài)、等待/阻塞狀態(tài)和死亡狀態(tài)。在本節(jié)中就來對每一個(gè)狀態(tài)進(jìn)行講解。,13.4.1 新建狀態(tài),當(dāng)一個(gè)線程對象被創(chuàng)建后,線程就處于新建狀態(tài)。在新建狀態(tài)中的線程對象從嚴(yán)格意義上看還只是一個(gè)普通的對象,它還不是一個(gè)獨(dú)立的線程。處于新建狀態(tài)中的線程被調(diào)用start方法后就會進(jìn)入準(zhǔn)備狀態(tài)。從新建狀態(tài)中只

14、能進(jìn)入準(zhǔn)備狀態(tài),并且不能從其他狀態(tài)進(jìn)行新建狀態(tài)。新建狀態(tài)是線程生命周期的第一個(gè)狀態(tài)。,13.4.2 準(zhǔn)備狀態(tài),處于新建狀態(tài)中的線程被調(diào)用start方法就會進(jìn)入準(zhǔn)備狀態(tài)。處于準(zhǔn)備狀態(tài)下的線程隨時(shí)都可能被系統(tǒng)選擇進(jìn)入運(yùn)行狀態(tài),從而執(zhí)行線程??赡芡瑫r(shí)有多個(gè)線程處于準(zhǔn)備狀態(tài),對于哪一個(gè)線程將進(jìn)入運(yùn)行狀態(tài)是不確定的。線程從新建狀態(tài)進(jìn)入到準(zhǔn)備狀態(tài)后是不可能再進(jìn)入新建狀態(tài)的。在等待/阻塞狀態(tài)中的線程被解除等待和阻塞后將不直接進(jìn)入運(yùn)行狀態(tài),而是首先進(jìn)入準(zhǔn)備狀態(tài),讓系統(tǒng)來選擇哪一個(gè)線程進(jìn)入運(yùn)行狀態(tài)。,13.4.3 運(yùn)行狀態(tài),處于準(zhǔn)備狀態(tài)中的線程一旦被系統(tǒng)選中,使線程獲取了CPU時(shí)間,就會進(jìn)入運(yùn)行狀態(tài)。在運(yùn)行狀態(tài)

15、中將執(zhí)行線程類run方法中的程序語句。線程進(jìn)入運(yùn)行狀態(tài)后也不是一下執(zhí)行結(jié)束的,線程在運(yùn)行狀態(tài)下隨時(shí)都可能被調(diào)度程序調(diào)度回準(zhǔn)備狀態(tài)。在運(yùn)行狀態(tài)下還可以讓線程進(jìn)入到等待/阻塞狀態(tài)。在通常的單核CPU中,在同一時(shí)刻只有一個(gè)線程處于運(yùn)行狀態(tài)的。在多核的CPU中,就可能兩個(gè)線程或者更多的線程同時(shí)處于運(yùn)行狀態(tài),這也是多核CPU運(yùn)行速度快的原因。,13.4.4 等待/阻塞狀態(tài),在Java中定義了許多線程調(diào)度的方法,包括睡眠、阻塞、掛起和等待,這些方法將在后面的調(diào)度章節(jié)中講解。使用這些方法都會將處于運(yùn)行狀態(tài)的線程調(diào)度到等待/阻塞狀態(tài)。處于等待/阻塞狀態(tài)的線程被解除后,不會立即回到運(yùn)行狀態(tài),而是首先進(jìn)入準(zhǔn)備狀態(tài)

16、,等待系統(tǒng)的調(diào)度。,13.4.5 死亡狀態(tài),當(dāng)線程中的run方法執(zhí)行結(jié)束后,或者程序發(fā)生異常終止運(yùn)行后,線程會進(jìn)入死亡狀態(tài)。處于死亡狀態(tài)的線程不能再使用start方法啟動(dòng)線程,這在前面的學(xué)習(xí)中已經(jīng)學(xué)到了這一點(diǎn)。但是這不代表處于死亡狀態(tài)的線程不能再被使用,它也是可以再被使用的,只是將被作為普通的類來使用。 注意:線程生命周期的問題,有些讀者會覺得很容易的。線程生命周期的問題在后面的學(xué)習(xí)中會經(jīng)常使用到,只有能充分了解線程的生命周期,才能更好地理解后面的內(nèi)容。,13.5 線程的調(diào)度,通過系統(tǒng)自動(dòng)調(diào)度,線程的執(zhí)行順序是沒有保障的。在Java中定義了一些線程調(diào)度的方法,使用這些方法在一定程序上對線程進(jìn)行

17、調(diào)度,使用這些方法只是給線程一個(gè)建議,具體是否能夠成功,也是沒有保障的。線程調(diào)度的方法有幾個(gè),包括睡眠方法、設(shè)置優(yōu)先級、讓步方法等,在本節(jié)中就來學(xué)習(xí)這些方法的使用。,13.5.1 睡眠方法,當(dāng)線程處于運(yùn)行狀態(tài)時(shí),調(diào)用sleep睡眠方法將使線程從運(yùn)行狀態(tài)進(jìn)入等待/阻塞狀態(tài),從而使程序停止運(yùn)行。sleep睡眠方法是具有一個(gè)時(shí)間參數(shù)的,當(dāng)經(jīng)過這么長時(shí)間后,線程將進(jìn)入準(zhǔn)備狀態(tài),等待系統(tǒng)的調(diào)度。從而可以看出,當(dāng)線程調(diào)用睡眠方法后,要想回到運(yùn)行狀態(tài),需要的時(shí)間要比指定的睡眠時(shí)間長。 sleep方法被重載,存在兩種形式,sleep方法的基本語法格式如下所示。 public static void sleep

18、(long millis)throws InterruptedException; public static void sleep(long millis,int nanos)throws InterruptedException;,使用這兩個(gè)sleep方法都能使線程進(jìn)入睡眠狀態(tài),mills參數(shù)表示線程睡眠的毫秒數(shù),nanos參數(shù)表示線程睡眠的納秒數(shù)。sleep方法是一個(gè)靜態(tài)的方法,所以sleep方法不是依賴于某一個(gè)對象的,它的位置是比較隨意的。當(dāng)在線程中執(zhí)行sleep方法,則該線程就進(jìn)入睡眠狀態(tài)。要想讓某一個(gè)線程進(jìn)入睡眠狀態(tài),并不是讓該線程調(diào)用sleep方法,而只是讓該線程執(zhí)行sleep方法。sleep方法是可

溫馨提示

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

評論

0/150

提交評論