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

下載本文檔

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

文檔簡介

1、 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)第第10章章多線程多線程現(xiàn)代操作系統(tǒng)通常都支持多線程。多線程技術(shù)是現(xiàn)代操作系統(tǒng)通常都支持多線程。多線程技術(shù)是Java平臺的平臺的一個(gè)重要技術(shù)優(yōu)勢?;谝粋€(gè)重要技術(shù)優(yōu)勢?;贘ava多線程技術(shù)可以在應(yīng)用程序中多線程技術(shù)可以在應(yīng)用程序中創(chuàng)建多個(gè)可執(zhí)行代碼單元,讓創(chuàng)建多個(gè)可執(zhí)行代碼單元,讓CPU同時(shí)執(zhí)行這些代碼單元。同時(shí)執(zhí)行這些代碼單元。本章將詳細(xì)介紹本章將詳細(xì)介紹Java多線程編程的方法和技巧,包括線程的多線程編程的方法和技巧,包括線程的基本概念、線程的創(chuàng)建和生命周期、線程同步等知識。本章基本概念、線程的創(chuàng)建和生命周期、線程同步等知識。本章內(nèi)容:內(nèi)容:10.1線程的概念

2、線程的概念10.2線程的實(shí)現(xiàn)線程的實(shí)現(xiàn)10.3線程同步線程同步 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.1線程的概念線程的概念10.1.1多線程編程的優(yōu)勢多線程編程的優(yōu)勢10.1.2多線程編程的難點(diǎn)多線程編程的難點(diǎn) JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.1.1多線程編程的優(yōu)勢多線程編程的優(yōu)勢1充分利用充分利用CPU資源資源現(xiàn)在主流的現(xiàn)在主流的CPU都是多核心。如果采用單線程編程,則程序都是多核心。如果采用單線程編程,則程序運(yùn)行時(shí)只會使用一個(gè)運(yùn)行時(shí)只會使用一個(gè)CPU核心。而多線程程序會充分利用所有核心。而多線程程序會充分利用所有的的CPU核心進(jìn)行運(yùn)算,有效提高程序的運(yùn)行速度。核心進(jìn)行運(yùn)算,有效提高程序的運(yùn)行速

3、度。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.1.1多線程編程的優(yōu)勢多線程編程的優(yōu)勢2簡化異步事件的處理簡化異步事件的處理在進(jìn)行在進(jìn)行“服務(wù)器服務(wù)器-客戶端客戶端”編程時(shí),若采用單線程來處理,當(dāng)編程時(shí),若采用單線程來處理,當(dāng)監(jiān)聽線程接收到一個(gè)客戶端請求后,開始讀取客戶端發(fā)來的數(shù)監(jiān)聽線程接收到一個(gè)客戶端請求后,開始讀取客戶端發(fā)來的數(shù)據(jù),讀取結(jié)束后,據(jù),讀取結(jié)束后,read()方法處于阻塞狀態(tài),無法處理其它請方法處于阻塞狀態(tài),無法處理其它請求。若使用非阻塞的求。若使用非阻塞的Socket連接和異步連接和異步I/O,則難于控制,易出,則難于控制,易出錯(cuò)。若服務(wù)器端采用多線程編程,為每個(gè)客戶端建立一個(gè)線程,錯(cuò)

4、。若服務(wù)器端采用多線程編程,為每個(gè)客戶端建立一個(gè)線程,監(jiān)聽這些線程處相關(guān)請求,此種模式最易實(shí)現(xiàn)。監(jiān)聽這些線程處相關(guān)請求,此種模式最易實(shí)現(xiàn)。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.1.1多線程編程的優(yōu)勢多線程編程的優(yōu)勢3使使GUI更有效率更有效率使用單線程處理使用單線程處理GUI事件,必須使用循環(huán)對隨時(shí)可能發(fā)生的事件,必須使用循環(huán)對隨時(shí)可能發(fā)生的GUI事件進(jìn)行掃描,在循環(huán)內(nèi)部除了掃描事件進(jìn)行掃描,在循環(huán)內(nèi)部除了掃描GUI事件外,還要執(zhí)事件外,還要執(zhí)行其他的程序代碼。若這些代碼太長,則行其他的程序代碼。若這些代碼太長,則GUI事件會被事件會被“凍凍結(jié)結(jié)”,直到這些代碼被執(zhí)行完為止?,F(xiàn)代的,直到這些代碼被

5、執(zhí)行完為止?,F(xiàn)代的GUI框架(如框架(如SWING、AWT和和SWT)中都使用了一個(gè)單獨(dú)的事件分派線程)中都使用了一個(gè)單獨(dú)的事件分派線程(eventdispatchthread,EDT)來對)來對GUI事件進(jìn)行掃描,可有事件進(jìn)行掃描,可有效降低事件處理的復(fù)雜性。效降低事件處理的復(fù)雜性。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.1.2多線程編程的難點(diǎn)多線程編程的難點(diǎn)1訪問共享資源訪問共享資源有時(shí)多個(gè)線程會訪問同一資源,若不做任何限制,讓多個(gè)線有時(shí)多個(gè)線程會訪問同一資源,若不做任何限制,讓多個(gè)線程以任意的調(diào)度順序?qū)υ撡Y源進(jìn)行任意的讀寫操作,則可能出程以任意的調(diào)度順序?qū)υ撡Y源進(jìn)行任意的讀寫操作,則可能出現(xiàn)丟

6、失修改、讀臟數(shù)據(jù)等錯(cuò)誤。因此,多線程訪問共享資源時(shí),現(xiàn)丟失修改、讀臟數(shù)據(jù)等錯(cuò)誤。因此,多線程訪問共享資源時(shí),必須通過加鎖實(shí)現(xiàn)互斥訪問。若加鎖方式不正確,則可能造成必須通過加鎖實(shí)現(xiàn)互斥訪問。若加鎖方式不正確,則可能造成死鎖,使程序無法繼續(xù)運(yùn)行。死鎖,使程序無法繼續(xù)運(yùn)行。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.1.2多線程編程的難點(diǎn)多線程編程的難點(diǎn)2線程間協(xié)作線程間協(xié)作有時(shí)多個(gè)線程必須相互配合才能完成復(fù)雜的計(jì)算任務(wù)。當(dāng)某有時(shí)多個(gè)線程必須相互配合才能完成復(fù)雜的計(jì)算任務(wù)。當(dāng)某個(gè)線程運(yùn)行了一部分代碼后,必須等待其它線程的計(jì)算結(jié)果才個(gè)線程運(yùn)行了一部分代碼后,必須等待其它線程的計(jì)算結(jié)果才能繼續(xù)運(yùn)行。線程通過傳遞消

7、息的方式將自己的狀態(tài)告知其它能繼續(xù)運(yùn)行。線程通過傳遞消息的方式將自己的狀態(tài)告知其它線程,收到消息的線程根據(jù)實(shí)際情況決定是繼續(xù)等待還是開始線程,收到消息的線程根據(jù)實(shí)際情況決定是繼續(xù)等待還是開始運(yùn)行。若同步方式不正確,可能導(dǎo)致最終的計(jì)算結(jié)果不正確。運(yùn)行。若同步方式不正確,可能導(dǎo)致最終的計(jì)算結(jié)果不正確。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.1.2多線程編程的難點(diǎn)多線程編程的難點(diǎn)3調(diào)試程序調(diào)試程序由于操作系統(tǒng)調(diào)度的隨機(jī)性,每次多線程程序的運(yùn)行順序都由于操作系統(tǒng)調(diào)度的隨機(jī)性,每次多線程程序的運(yùn)行順序都不一致。若程序有不一致。若程序有Bug,并不是每次運(yùn)行都會導(dǎo)致錯(cuò)誤的結(jié)果,并不是每次運(yùn)行都會導(dǎo)致錯(cuò)誤的結(jié)果,

8、某些調(diào)度順序可能會得到正確的結(jié)果。在調(diào)試程序時(shí),有可能某些調(diào)度順序可能會得到正確的結(jié)果。在調(diào)試程序時(shí),有可能該該Bug一直都無法重現(xiàn),大大增加了調(diào)試程序的難度。一直都無法重現(xiàn),大大增加了調(diào)試程序的難度。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2線程的實(shí)現(xiàn)線程的實(shí)現(xiàn)10.2.1創(chuàng)建創(chuàng)建Java線程線程10.2.2Java線程的狀態(tài)線程的狀態(tài)10.2.3Java線程的優(yōu)先級線程的優(yōu)先級10.2.4守護(hù)線程守護(hù)線程10.2.5終止另一個(gè)線程終止另一個(gè)線程 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.1創(chuàng)建創(chuàng)建Java線程線程在在Java中創(chuàng)建線程有兩種方法:繼承中創(chuàng)建線程有兩種方法:繼承Thread類或?qū)崿F(xiàn)類或?qū)?/p>

9、現(xiàn)Runnable接口。接口。1繼承繼承Thread類創(chuàng)建線程類創(chuàng)建線程創(chuàng)建并啟動線程步驟如下:創(chuàng)建并啟動線程步驟如下:(1)通過繼承)通過繼承Thread類的方式定義自己的線程類。類的方式定義自己的線程類。(2)重載)重載run()方法,在方法,在run()方法中實(shí)現(xiàn)線程的功能。方法中實(shí)現(xiàn)線程的功能。(3)用自定義的線程類創(chuàng)建一個(gè)對象。)用自定義的線程類創(chuàng)建一個(gè)對象。(4)調(diào)用該對象的)調(diào)用該對象的start()方法啟動線程。方法啟動線程。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.1創(chuàng)建創(chuàng)建Java線程線程需要特別注意的是,盡管線程的功能在需要特別注意的是,盡管線程的功能在run()方法中實(shí)現(xiàn),

10、但方法中實(shí)現(xiàn),但不要直接調(diào)用該方法,而應(yīng)該調(diào)用不要直接調(diào)用該方法,而應(yīng)該調(diào)用start()方法,方法,start()方法會啟方法會啟動一個(gè)新的線程并執(zhí)行動一個(gè)新的線程并執(zhí)行run()方法。若直接調(diào)用方法。若直接調(diào)用run()方法,該方法,該方法只會在當(dāng)前線程內(nèi)執(zhí)行,而不會啟動新線程。方法只會在當(dāng)前線程內(nèi)執(zhí)行,而不會啟動新線程?!纠?0-1】通過繼承通過繼承Thread類的方式定義一個(gè)能打印字母的類的方式定義一個(gè)能打印字母的線程類,該類通過構(gòu)造方法接收一個(gè)大寫字母,在運(yùn)行時(shí)每行線程類,該類通過構(gòu)造方法接收一個(gè)大寫字母,在運(yùn)行時(shí)每行打印該字母打印該字母20次,共打印次,共打印100行。創(chuàng)建并運(yùn)行

11、行。創(chuàng)建并運(yùn)行3個(gè)該線程的實(shí)例。個(gè)該線程的實(shí)例。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.1創(chuàng)建創(chuàng)建Java線程線程2實(shí)現(xiàn)實(shí)現(xiàn)Runnable接口創(chuàng)建線程接口創(chuàng)建線程創(chuàng)建并啟動線程步驟如下:創(chuàng)建并啟動線程步驟如下:(1)通過實(shí)現(xiàn))通過實(shí)現(xiàn)Runnable接口的方式定義自己的線程類接口的方式定義自己的線程類(2)重載)重載run()方法,在方法,在run()方法中實(shí)現(xiàn)線程的功能。方法中實(shí)現(xiàn)線程的功能。(3)用自定義的線程類創(chuàng)建一個(gè)對象。)用自定義的線程類創(chuàng)建一個(gè)對象。(4)用)用Thread類創(chuàng)建一個(gè)對象,將類創(chuàng)建一個(gè)對象,將(3)創(chuàng)建的對象傳給創(chuàng)建的對象傳給Thread類的構(gòu)造方法。類的構(gòu)造方法。

12、(5)調(diào)用)調(diào)用Thread對象的對象的start()方法啟動線程方法啟動線程 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.2Java線程的狀態(tài)線程的狀態(tài) JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.2Java線程的狀態(tài)線程的狀態(tài)1新建狀態(tài)(新建狀態(tài)(New)當(dāng)使用當(dāng)使用new操作符創(chuàng)建一個(gè)線程對象時(shí),該線程處于新建狀態(tài)。操作符創(chuàng)建一個(gè)線程對象時(shí),該線程處于新建狀態(tài)。此時(shí)它只是一個(gè)普通的對象,并不具備線程的特點(diǎn)。在此狀態(tài)此時(shí)它只是一個(gè)普通的對象,并不具備線程的特點(diǎn)。在此狀態(tài)下,可對該對象進(jìn)行一些初始化設(shè)置,為將來作為線程運(yùn)行做下,可對該對象進(jìn)行一些初始化設(shè)置,為將來作為線程運(yùn)行做準(zhǔn)備。準(zhǔn)備。2可執(zhí)行狀態(tài)(可執(zhí)

13、行狀態(tài)(Runnable)調(diào)用調(diào)用start()方法后線程就處于可執(zhí)行狀態(tài)。該狀態(tài)只說明線程方法后線程就處于可執(zhí)行狀態(tài)。該狀態(tài)只說明線程可以被執(zhí)行,而不是說它正在可以被執(zhí)行,而不是說它正在CPU中執(zhí)行。大多數(shù)處于中執(zhí)行。大多數(shù)處于Runnable狀態(tài)的線程都位于等待隊(duì)列中,等待操作系統(tǒng)的調(diào)度。狀態(tài)的線程都位于等待隊(duì)列中,等待操作系統(tǒng)的調(diào)度。在在Java中并沒有為正在中并沒有為正在CPU中執(zhí)行的線程單獨(dú)設(shè)置一個(gè)狀態(tài),中執(zhí)行的線程單獨(dú)設(shè)置一個(gè)狀態(tài),它們?nèi)匀皇撬鼈內(nèi)匀皇荝unnable狀態(tài)。當(dāng)線程開始執(zhí)行后,并不會一直占狀態(tài)。當(dāng)線程開始執(zhí)行后,并不會一直占有有CPU,操作系統(tǒng)會將它切換到其他狀態(tài),從

14、而給其它線程一,操作系統(tǒng)會將它切換到其他狀態(tài),從而給其它線程一個(gè)執(zhí)行的機(jī)會。個(gè)執(zhí)行的機(jī)會。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.2Java線程的狀態(tài)線程的狀態(tài)3阻塞狀態(tài)(阻塞狀態(tài)(Blocked)當(dāng)線程想要獲得一個(gè)鎖,而這個(gè)鎖被其它線程占有,則該線當(dāng)線程想要獲得一個(gè)鎖,而這個(gè)鎖被其它線程占有,則該線程進(jìn)入阻塞狀態(tài)。當(dāng)其它線程釋放了鎖,而調(diào)度機(jī)制又允許此程進(jìn)入阻塞狀態(tài)。當(dāng)其它線程釋放了鎖,而調(diào)度機(jī)制又允許此線程獲得該鎖,則線程就從阻塞狀態(tài)變更為可執(zhí)行狀態(tài)。線程獲得該鎖,則線程就從阻塞狀態(tài)變更為可執(zhí)行狀態(tài)。4等待狀態(tài)(等待狀態(tài)(Waiting)為實(shí)現(xiàn)同步,線程執(zhí)行時(shí)需要檢測一些條件,只有條件得到為

15、實(shí)現(xiàn)同步,線程執(zhí)行時(shí)需要檢測一些條件,只有條件得到滿足才能繼續(xù)執(zhí)行。若條件未得到滿足,則線程進(jìn)入等待狀態(tài)。滿足才能繼續(xù)執(zhí)行。若條件未得到滿足,則線程進(jìn)入等待狀態(tài)。當(dāng)其它線程完成某些任務(wù)后,會發(fā)出一個(gè)信號喚醒處于等待狀當(dāng)其它線程完成某些任務(wù)后,會發(fā)出一個(gè)信號喚醒處于等待狀態(tài)的線程,這些線程再重新檢測條件是否得到了滿足。態(tài)的線程,這些線程再重新檢測條件是否得到了滿足。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.2Java線程的狀態(tài)線程的狀態(tài)5計(jì)時(shí)等待狀態(tài)(計(jì)時(shí)等待狀態(tài)(TimedWaiting)某些方法擁有計(jì)時(shí)參數(shù),調(diào)用這些方法可使線程就進(jìn)入計(jì)時(shí)某些方法擁有計(jì)時(shí)參數(shù),調(diào)用這些方法可使線程就進(jìn)入計(jì)時(shí)等待狀

16、態(tài)。當(dāng)計(jì)時(shí)結(jié)束,線程變更為可執(zhí)行狀態(tài)。調(diào)用等待狀態(tài)。當(dāng)計(jì)時(shí)結(jié)束,線程變更為可執(zhí)行狀態(tài)。調(diào)用Thread.sleep(time)方法可使線程進(jìn)入計(jì)時(shí)等待狀態(tài)。應(yīng)注意,方法可使線程進(jìn)入計(jì)時(shí)等待狀態(tài)。應(yīng)注意,sleep()是靜態(tài)方法,須通過是靜態(tài)方法,須通過Thread類直接調(diào)用,參數(shù)是等待的類直接調(diào)用,參數(shù)是等待的時(shí)長,以毫秒為單位。時(shí)長,以毫秒為單位。6終止?fàn)顟B(tài)(終止?fàn)顟B(tài)(Terminated)當(dāng)當(dāng)run()方法終結(jié)后,該線程就進(jìn)入終止?fàn)顟B(tài)。方法終結(jié)后,該線程就進(jìn)入終止?fàn)顟B(tài)。run()方法的終方法的終結(jié)包括自然終結(jié)和異常終結(jié)。自然終結(jié)是指結(jié)包括自然終結(jié)和異常終結(jié)。自然終結(jié)是指run()方法的最后

17、一方法的最后一行代碼執(zhí)行完畢正常結(jié)束,異常終結(jié)是指在執(zhí)行過程中因出現(xiàn)行代碼執(zhí)行完畢正常結(jié)束,異常終結(jié)是指在執(zhí)行過程中因出現(xiàn)異常而結(jié)束。異常而結(jié)束。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.3Java線程的優(yōu)先級線程的優(yōu)先級Java中每個(gè)線程都擁有優(yōu)先級。默認(rèn)情況下,線程的優(yōu)先級中每個(gè)線程都擁有優(yōu)先級。默認(rèn)情況下,線程的優(yōu)先級繼承自創(chuàng)建它的那個(gè)線程。可以使用繼承自創(chuàng)建它的那個(gè)線程??梢允褂胹etPriority()方法來提高或方法來提高或降低一個(gè)線程的優(yōu)先級。在降低一個(gè)線程的優(yōu)先級。在Thread類中預(yù)定義了類中預(yù)定義了3個(gè)優(yōu)先級常個(gè)優(yōu)先級常量:量:MIN_PRIORITY:線程的最低優(yōu)先級,其值為

18、整數(shù):線程的最低優(yōu)先級,其值為整數(shù)1NORM_PRIORITY:線程默認(rèn)優(yōu)先級,其值為整數(shù):線程默認(rèn)優(yōu)先級,其值為整數(shù)5MAX_PRIORITY:線程的最高優(yōu)先級,其值為整數(shù):線程的最高優(yōu)先級,其值為整數(shù)10 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.3Java線程的優(yōu)先級線程的優(yōu)先級在設(shè)置線程優(yōu)先級時(shí),可以使用上述常量,也可指定一個(gè)在設(shè)置線程優(yōu)先級時(shí),可以使用上述常量,也可指定一個(gè)1-10范圍內(nèi)的整數(shù)作為優(yōu)先級。需要注意的是,范圍內(nèi)的整數(shù)作為優(yōu)先級。需要注意的是,Java中線程優(yōu)先中線程優(yōu)先級高度依賴操作系統(tǒng)的具體實(shí)現(xiàn),在不同的操作系統(tǒng)中,級高度依賴操作系統(tǒng)的具體實(shí)現(xiàn),在不同的操作系統(tǒng)中,Java

19、處理線程優(yōu)先級的方式并不一樣。例如在處理線程優(yōu)先級的方式并不一樣。例如在Windows系統(tǒng)中,操系統(tǒng)中,操作系統(tǒng)本身只支持整數(shù)作系統(tǒng)本身只支持整數(shù)1-7作為優(yōu)先級,因此,作為優(yōu)先級,因此,Java線程的優(yōu)線程的優(yōu)先級先級1-10會被映射到會被映射到1-7的范圍內(nèi),即某些不同的的范圍內(nèi),即某些不同的Java優(yōu)先優(yōu)先級會被映射為相同的級會被映射為相同的Windows優(yōu)先級。在優(yōu)先級。在Linux系統(tǒng)中,系統(tǒng)中,Sun公公司的虛擬機(jī)會忽略優(yōu)先級設(shè)置,所有線程的優(yōu)先級都相同。司的虛擬機(jī)會忽略優(yōu)先級設(shè)置,所有線程的優(yōu)先級都相同。操作系統(tǒng)進(jìn)行線程調(diào)度時(shí),會優(yōu)先選擇級別高的線程,因此操作系統(tǒng)進(jìn)行線程調(diào)度時(shí),

20、會優(yōu)先選擇級別高的線程,因此對優(yōu)先級的使用應(yīng)特別謹(jǐn)慎,設(shè)置不當(dāng)將導(dǎo)致某些線程永遠(yuǎn)得對優(yōu)先級的使用應(yīng)特別謹(jǐn)慎,設(shè)置不當(dāng)將導(dǎo)致某些線程永遠(yuǎn)得不到運(yùn)行。另外,絕對不要讓程序結(jié)果的正確性依賴于優(yōu)先級不到運(yùn)行。另外,絕對不要讓程序結(jié)果的正確性依賴于優(yōu)先級的設(shè)置。若無特殊情況,不要修改線程的默認(rèn)優(yōu)先級。的設(shè)置。若無特殊情況,不要修改線程的默認(rèn)優(yōu)先級。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.4守護(hù)線程守護(hù)線程守護(hù)線程(守護(hù)線程(DaemonThread)是指程序運(yùn)行在后臺提供服務(wù))是指程序運(yùn)行在后臺提供服務(wù)的線程,此類線程并不屬于程序中不可或缺的部分。因此,當(dāng)?shù)木€程,此類線程并不屬于程序中不可或缺的部分。因此

21、,當(dāng)所有的非守護(hù)線程結(jié)束后,程序結(jié)束并終結(jié)所有守護(hù)線程。反所有的非守護(hù)線程結(jié)束后,程序結(jié)束并終結(jié)所有守護(hù)線程。反過來講,只要任何非守護(hù)線程還在運(yùn)行,程序就不會終止。計(jì)過來講,只要任何非守護(hù)線程還在運(yùn)行,程序就不會終止。計(jì)時(shí)器(時(shí)器(Timer)線程是典型的守護(hù)線程,它的存在就是為其它)線程是典型的守護(hù)線程,它的存在就是為其它線程提供計(jì)時(shí)服務(wù),該線程本身并無明確的終止條件,當(dāng)主線線程提供計(jì)時(shí)服務(wù),該線程本身并無明確的終止條件,當(dāng)主線程結(jié)束后,作為守護(hù)線程,它會被自動終止。需要注意,絕對程結(jié)束后,作為守護(hù)線程,它會被自動終止。需要注意,絕對不要在守護(hù)線程中訪問文件或數(shù)據(jù)庫等持久化資源,因?yàn)槭刈o(hù)不要

22、在守護(hù)線程中訪問文件或數(shù)據(jù)庫等持久化資源,因?yàn)槭刈o(hù)線程可以在任意時(shí)刻被終止,有可能對持久化資源造成錯(cuò)誤的線程可以在任意時(shí)刻被終止,有可能對持久化資源造成錯(cuò)誤的修改。調(diào)用修改。調(diào)用setDaemon(true)方法可以將一個(gè)線程設(shè)置為守護(hù)線方法可以將一個(gè)線程設(shè)置為守護(hù)線程。程。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.5終止另一個(gè)線程終止另一個(gè)線程在早期的在早期的Java版本中提供了版本中提供了stop()方法強(qiáng)行終止一個(gè)線程。由方法強(qiáng)行終止一個(gè)線程。由于可能造成數(shù)據(jù)不一致,該方法已廢棄。現(xiàn)在無法強(qiáng)行終止一于可能造成數(shù)據(jù)不一致,該方法已廢棄。現(xiàn)在無法強(qiáng)行終止一個(gè)線程,只能向該線程發(fā)消息,請求它終止。

23、收到消息后,線個(gè)線程,只能向該線程發(fā)消息,請求它終止。收到消息后,線程可自行決定是立刻終止還是繼續(xù)運(yùn)行。程可自行決定是立刻終止還是繼續(xù)運(yùn)行。若線程若線程t1想要終止線程想要終止線程t2,則應(yīng)調(diào)用,則應(yīng)調(diào)用t2的的interrupt()方法,向方法,向t2發(fā)送消息。發(fā)送消息。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.5終止另一個(gè)線程終止另一個(gè)線程每個(gè)線程都有一個(gè)內(nèi)部狀態(tài),稱為中斷狀態(tài)(每個(gè)線程都有一個(gè)內(nèi)部狀態(tài),稱為中斷狀態(tài)(interruptedstatus),該狀態(tài)的初始值為),該狀態(tài)的初始值為false。當(dāng)調(diào)用了。當(dāng)調(diào)用了interrupt方法后,方法后,該狀態(tài)被設(shè)置為該狀態(tài)被設(shè)置為true。若

24、線程。若線程t2同意同意t1的終止請求,只需在的終止請求,只需在run()方法中調(diào)用方法中調(diào)用isInterrupted()方法檢測該狀態(tài),若為方法檢測該狀態(tài),若為true則自我終則自我終結(jié)。代碼結(jié)構(gòu)如下:結(jié)。代碼結(jié)構(gòu)如下:publicvoidrun()while(!Thread.currentThread().isInterrupted()/實(shí)現(xiàn)線程的功能實(shí)現(xiàn)線程的功能 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.5終止另一個(gè)線程終止另一個(gè)線程若線程若線程t2處于阻塞狀態(tài)或計(jì)時(shí)等待狀態(tài),執(zhí)行處于阻塞狀態(tài)或計(jì)時(shí)等待狀態(tài),執(zhí)行errupt()會會拋出拋出InterruptedExceptio

25、n異常。因此,對于可能進(jìn)入阻塞狀態(tài)異常。因此,對于可能進(jìn)入阻塞狀態(tài)的線程,還必須捕捉該異常才能正確處理終止請求。完整的處的線程,還必須捕捉該異常才能正確處理終止請求。完整的處理終止請求的代碼結(jié)構(gòu)下:理終止請求的代碼結(jié)構(gòu)下: JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.5終止另一個(gè)線程終止另一個(gè)線程publicvoidrun()trywhile(!Thread.currentThread().isInterrupted()&其他條件其他條件)/實(shí)現(xiàn)線程的功能實(shí)現(xiàn)線程的功能catch(InterruptedExceptione)/做一些異常處理工作做一些異常處理工作finally/做一些線程結(jié)束前

26、的清理工作做一些線程結(jié)束前的清理工作 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.2.5終止另一個(gè)線程終止另一個(gè)線程【例例10-2】自定義一個(gè)線程類,打印自定義一個(gè)線程類,打印A-Z共共26個(gè)字母,相鄰個(gè)字母,相鄰兩個(gè)字母的打印時(shí)間間隔為兩個(gè)字母的打印時(shí)間間隔為1秒。在主程序中啟動該線程,于秒。在主程序中啟動該線程,于8秒后終止該線程。秒后終止該線程。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.3線程同步線程同步10.3.1同步訪問共享資源同步訪問共享資源10.3.2協(xié)作完成任務(wù)協(xié)作完成任務(wù) JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.3.1同步訪問共享資源同步訪問共享資源當(dāng)多個(gè)線程對共享數(shù)據(jù)進(jìn)行修改時(shí),若操作系統(tǒng)在某些特定當(dāng)

27、多個(gè)線程對共享數(shù)據(jù)進(jìn)行修改時(shí),若操作系統(tǒng)在某些特定階段進(jìn)行線程切換,則會導(dǎo)致對數(shù)據(jù)的錯(cuò)誤修改。階段進(jìn)行線程切換,則會導(dǎo)致對數(shù)據(jù)的錯(cuò)誤修改?!纠?0-3】開啟開啟2個(gè)線程,對長度為個(gè)線程,對長度為2的整型數(shù)組的整型數(shù)組a進(jìn)行修改,進(jìn)行修改,初始狀態(tài)下初始狀態(tài)下a0=4000,a1=4000。線程。線程1每次從每次從a0減去一個(gè)減去一個(gè)值,并將該值加到值,并將該值加到a1上。線程上。線程2每次從每次從a1減去一個(gè)值,并將減去一個(gè)值,并將該值加到該值加到a0上。在主程序中對數(shù)組上。在主程序中對數(shù)組a進(jìn)行求和,檢驗(yàn)進(jìn)行求和,檢驗(yàn)a0+a1是否等于是否等于8000。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.3

28、.1同步訪問共享資源同步訪問共享資源之所以會出現(xiàn)錯(cuò)誤,是因?yàn)椴僮飨到y(tǒng)在進(jìn)行線程調(diào)度時(shí)只保之所以會出現(xiàn)錯(cuò)誤,是因?yàn)椴僮飨到y(tǒng)在進(jìn)行線程調(diào)度時(shí)只保證原子操作的完整執(zhí)行。在證原子操作的完整執(zhí)行。在Java中對基本數(shù)據(jù)類型(不包括中對基本數(shù)據(jù)類型(不包括long和和double)進(jìn)行賦值或返回的操作是原子操作,其他)進(jìn)行賦值或返回的操作是原子操作,其他Java語句均可轉(zhuǎn)化為多條原子指令。因此,線程調(diào)度很可能發(fā)生在語句均可轉(zhuǎn)化為多條原子指令。因此,線程調(diào)度很可能發(fā)生在Java語句執(zhí)行到一半的時(shí)刻。例如,語句執(zhí)行到一半的時(shí)刻。例如,Java語句語句“data0+=x”可轉(zhuǎn)化為如下可轉(zhuǎn)化為如下3條原子指令:條

29、原子指令:1.將將data0的值讀入寄存器的值讀入寄存器2.將寄存器的值增加將寄存器的值增加x3.將寄存器的值寫回到將寄存器的值寫回到data0中中 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.3.1同步訪問共享資源同步訪問共享資源若按照如下序列進(jìn)行線程調(diào)度,則有可能產(chǎn)生如圖若按照如下序列進(jìn)行線程調(diào)度,則有可能產(chǎn)生如圖10-4顯示的結(jié)果。顯示的結(jié)果。假設(shè)程序運(yùn)行一段時(shí)間后,假設(shè)程序運(yùn)行一段時(shí)間后,a0=3950,a1=40501.線程一將線程一將a0的值減的值減3,修改為,修改為3947。2.線程一將線程一將a1的值的值4050讀入寄存器。讀入寄存器。3.線程一將寄存器的值加線程一將寄存器的值加3,修改為

30、,修改為4053。-操作系統(tǒng)進(jìn)行線程切換操作系統(tǒng)進(jìn)行線程切換-4.線程二將線程二將a1的值的值4050讀入寄存器讀入寄存器5.線程二將寄存器的值減線程二將寄存器的值減10,修改為,修改為4040-操作系統(tǒng)進(jìn)行線程切換操作系統(tǒng)進(jìn)行線程切換-6.線程一將寄存器的值寫回到線程一將寄存器的值寫回到a1,此時(shí),此時(shí)a1的值為的值為4053。線程一轉(zhuǎn)移數(shù)據(jù)操。線程一轉(zhuǎn)移數(shù)據(jù)操作完成。作完成。-操作系統(tǒng)進(jìn)行線程切換操作系統(tǒng)進(jìn)行線程切換-7.線程二將寄存器的值寫回線程二將寄存器的值寫回a1,此時(shí),此時(shí)a1的值為的值為40408.線程二對線程二對a0的值加的值加10,修改為,修改為3957。線程二轉(zhuǎn)移數(shù)據(jù)。線程

31、二轉(zhuǎn)移數(shù)據(jù)操作完成操作完成此時(shí)主程序?qū)Υ藭r(shí)主程序?qū)0和和a1進(jìn)行求和,可得進(jìn)行求和,可得3957+4040=7997。 JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.3.1同步訪問共享資源同步訪問共享資源可通過為對象加鎖的方式避免此類錯(cuò)誤,只有獲得鎖的線程可通過為對象加鎖的方式避免此類錯(cuò)誤,只有獲得鎖的線程才可以訪問該對象,未獲得鎖的線程將進(jìn)入阻塞狀態(tài),直到其才可以訪問該對象,未獲得鎖的線程將進(jìn)入阻塞狀態(tài),直到其它對象釋放鎖。它對象釋放鎖。Java提供了提供了synchronized關(guān)鍵字為對象加鎖。關(guān)鍵字為對象加鎖。若在例若在例10-3中對數(shù)組中對數(shù)組data加鎖,只有獲得鎖的線程才能修改數(shù)加鎖,只有獲

32、得鎖的線程才能修改數(shù)據(jù),則可實(shí)現(xiàn)同步訪問,不會破壞數(shù)組據(jù),則可實(shí)現(xiàn)同步訪問,不會破壞數(shù)組a的數(shù)據(jù)。只需將例的數(shù)據(jù)。只需將例10-3中第中第2628行代碼替換為如下代碼。行代碼替換為如下代碼。synchronized(data)/為數(shù)組為數(shù)組data加鎖加鎖intx=rand.nextInt(10)+1;datai-=x;dataj+=x; JAVA 程序設(shè)計(jì)程序設(shè)計(jì)10.3.1同步訪問共享資源同步訪問共享資源synchronized關(guān)鍵字也可用于修飾方法,可對該方法所屬的對關(guān)鍵字也可用于修飾方法,可對該方法所屬的對象進(jìn)行加鎖。例象進(jìn)行加鎖。例10-3中可將數(shù)組中可將數(shù)組a封裝為類,在類的內(nèi)部實(shí)現(xiàn)轉(zhuǎn)封裝為類,在類的內(nèi)部實(shí)現(xiàn)轉(zhuǎn)移數(shù)據(jù)及求和的方法,并用移數(shù)據(jù)及求和的方法,并用synchronized關(guān)鍵字修飾這些方法。關(guān)鍵字修飾這些方法。Java5.0中提供了中提供了ReentrantLock類,既可實(shí)現(xiàn)類,既可實(shí)

溫馨提示

  • 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

提交評論