




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
第三章線程/進(jìn)程安全第一頁,共四十五頁。進(jìn)程和線程是兩個范圍不同的概念。進(jìn)程是程序在計算機(jī)上的一次執(zhí)行活動。運行一個程序,相當(dāng)于啟動了一個進(jìn)程。進(jìn)程是操作系統(tǒng)進(jìn)行資源分配的單位,通俗地講,是一個正在執(zhí)行的程序。線程是進(jìn)程中的一個實體,是被系統(tǒng)獨立調(diào)度和分派的基本單位,它可與同屬一個進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源。一個線程可以創(chuàng)建和撤消另一個線程,同一進(jìn)程中的多個線程之間可以并發(fā)執(zhí)行。比如,一個在線播放軟件,在播放歌曲的同時還可以進(jìn)行下載,就可認(rèn)為這兩件工作由不同的線程完成。第二頁,共四十五頁。線程和進(jìn)程的開發(fā)和相關(guān)操作,在程序設(shè)計中具有重要地位,線程和進(jìn)程的安全和系統(tǒng)的安全息息相關(guān)。對于不夠熟練的程序員來說,很容易出現(xiàn)安全隱患,而這些安全問題又具有不間斷發(fā)生,難于調(diào)試等特點。一般說來,線程的安全性主要來源于其運行的并發(fā)性和對資源的共享性;進(jìn)程的安全性主要在應(yīng)用級別,在于其對系統(tǒng)的威脅性,不過對于系統(tǒng)軟件的開發(fā)者,進(jìn)程安全的考慮需要更加深入。本章主要針對線程和進(jìn)程開發(fā)過程中的安全問題進(jìn)行講述,首先基于面向?qū)ο笳Z言,講解線程的的基本機(jī)制,然后講解線程操作過程中的幾個重要的安全問題:線程同步安全、線程協(xié)作安全、線程死鎖、線程控制,最后講解進(jìn)程安全。第三頁,共四十五頁。3.1線程機(jī)制第四頁,共四十五頁。3.1.1為什么需要線程由于Java在線程操作方面具有較好的面向?qū)ο筇匦?,也具有一定的代表性本章基于Java語言進(jìn)行講解。實際上,多線程最直觀的說法是:讓應(yīng)用程序看起來好像同時能做好幾件事情。為了表達(dá)這個問題,我們用一個案例來說明。比如,需要在控制臺上每隔1秒鐘打印一個歡迎信息。代碼如下所示:
publicclassP03_01{publicstaticvoidmain(String[]args){while(true){System.out.println("Welcome");try{Thread.sleep(1000);}catch(Exceptionex){}}System.out.println("其他工作");//代碼行1}}第五頁,共四十五頁。該程序似乎沒有什么問題,運行時,"Welcome"也能不斷打印。但是,我們發(fā)現(xiàn),打印函數(shù)中的while循環(huán)是個死循環(huán),也就是說,這個死循環(huán)不運行完畢,程序?qū)⒉荒茏髌渌虑?。比如,程序中的代碼行1永遠(yuǎn)也無法運行。這就給程序的功能形成了巨大的阻礙。在實際應(yīng)用開發(fā)的過程中,經(jīng)常會出現(xiàn)一個程序看起來同時作好幾件事情的情況,如程序進(jìn)行一個用時較長的計算,希望該計算進(jìn)行的時候,程序還可以做其他事情;程序進(jìn)行一個用時較長的計算,希望該計算進(jìn)行的時候,程序還可以做其他事情;軟件要能夠接受多個客戶的請求,而讓客戶感覺不出等待;媒體播放器在播放歌曲的同時也能下載電影;財務(wù)軟件在后臺進(jìn)行財務(wù)匯總的同時還能接受終端的請求;等等。第六頁,共四十五頁。在這些情況下,多線程就能夠起到巨大的作用。線程和進(jìn)程的關(guān)系很緊密,進(jìn)程和線程是兩個不同的概念,但是進(jìn)程的范圍大于線程。通俗地說,進(jìn)程就是一個程序,線程是這個程序能夠同時做的各件事情。比如,媒體播放機(jī)運行時就是一個進(jìn)程,而媒體播放機(jī)同時做的下載文件和播放歌曲,就是兩個線程。以上代碼如果用線程來進(jìn)行開發(fā),在Java語言里面,就可以用如P03_02.java的方式(其他語言類似)。第七頁,共四十五頁。運行,就會發(fā)現(xiàn),此時“打印歡迎信息”和“其他工作”就“同時”做了。第八頁,共四十五頁。3.1.2線程機(jī)制和生命周期每個程序至少自動擁有一個線程,稱為主線程。當(dāng)程序加載到內(nèi)存時,啟動主線程。從上節(jié)的程序可以看出,代碼行:實際上相當(dāng)于實例化一個新的線程對象,并運行該線程中的run()函數(shù)。該線程的運行并不影響主線程向下執(zhí)行,這是為什么呢?這是由于多線程的機(jī)制實際上相當(dāng)于CPU交替分配給不同的代碼段來運行:也就是說,某一個時間片,某線程運行,下一個時間片,另一個線程運行,各個線程都有搶占CPU的權(quán)利,至于決定哪個線程搶占,是操作系統(tǒng)需要考慮的事情。由于時間片的輪轉(zhuǎn)非???,用戶感覺不出各個線程搶占CPU的過程,看起來好像計算機(jī)在“同時”做好幾件事情。WelcomeThreadwt=newWelcomeThread();wt.start(); 第九頁,共四十五頁。一個線程有從創(chuàng)建、運行到消亡的過程,稱為線程的生命周期。用線程的狀態(tài)(state)表明線程處在生命周期的哪個階段。線程有創(chuàng)建、可運行、運行中、阻塞、死亡五種狀態(tài)。通過線程的控制與調(diào)度可使線程在這幾種狀態(tài)間轉(zhuǎn)化。這五種狀態(tài)詳細(xì)描述如下:1:創(chuàng)建狀態(tài):使用new運算符創(chuàng)建一個線程后。該線程僅僅是一個空對象,系統(tǒng)沒有分配資源。2:可運行狀態(tài):使用start()方法啟動一個線程后,系統(tǒng)分配了資源,使該線程處于可運行狀態(tài)(Runnable)。3:運行中狀態(tài):占有CPU,執(zhí)行線程的run()方法。4:阻塞狀態(tài):運行的線程因某種原因停止繼續(xù)運行。5:死亡狀態(tài):線程結(jié)束。第十頁,共四十五頁。線程的安全隱患可能出現(xiàn)在各個狀態(tài)。一般說來,線程的安全性來源于兩個方面:1:多個線程之間可能會共享進(jìn)程的內(nèi)存資源。2:CPU的某個時間片分配給哪個線程使用,默認(rèn)情況下無法由用戶控制。多線程的安全問題比較復(fù)雜,解決方法繁多,在這里我們闡述幾個比較典型的安全問題。第十一頁,共四十五頁。3.2線程同步安全第十二頁,共四十五頁。3.2.1線程同步默認(rèn)情況下,線程都是獨立的,而且異步執(zhí)行,線程中包含了運行時所需要的數(shù)據(jù)或方法,而不需要外部的資源或方法,也不必關(guān)心其它線程的狀態(tài)或行為。但是在多個線程在運行時共享數(shù)據(jù)的情況下,就需考慮其他線程的狀態(tài)和行為,否則就不能保證程序的運行結(jié)果的正確性。在某些項目中,經(jīng)常會出現(xiàn)線程同步的問題,即:多個線程在訪問同一資源時,會出現(xiàn)安全問題。本節(jié)基于一個簡單的案例,針對線程的同步問題進(jìn)行闡述。所謂同步,就是在發(fā)出一個功能調(diào)用時,在沒有得到結(jié)果之前,該調(diào)用就不返回,同時其它線程也不能調(diào)用這個方法。通俗地講,一個線程是否能夠搶占CPU,必須考慮另一個線程中的某種條件,而不能隨便讓操作系統(tǒng)按照默認(rèn)方式分配CPU,如果條件不具備,就應(yīng)該等待另一個線程運行,直到條件具備。第十三頁,共四十五頁。3.2.2案例分析給出一個案例:有若干張飛機(jī)票,2個線程去賣它們,要求沒有票時能夠提示:沒有票了。以最后剩下3張票為例。首先用傳統(tǒng)方法來編寫這段代碼。代碼如P03_03.java所示。運行,控制臺打印如下:
第十四頁,共四十五頁。這段程序貌似沒有問題。但是它是很不安全的,并且這種不安全性很難發(fā)現(xiàn),會給項目后期維護(hù)帶來巨大的代價。觀察程序中的代碼行1處的注釋,當(dāng)只剩下一張票時,線程1賣出了最后一張票,接著要運行ticketNum--,但在ticketNum--還沒來得及運行的時候,線程2有可能搶占CPU,來判斷當(dāng)前有無票可賣,此時,由于線程1還沒有將ticketNum--,當(dāng)然票數(shù)還是1,線程2判斷還可以買票,這樣,最后一張票賣出了兩次。當(dāng)然,上面的程序中,沒有給線程2以買票的機(jī)會,實際上票都由線程1賣出,我們看不出其中的問題。為了讓大家看清這個問題,我們模擬線程1和線程2交替賣票的情況。將P03_03.java的代碼改為P03_04.java:第十五頁,共四十五頁。該代碼中,增加了一行:程序休眠1000毫秒,讓另一個線程來搶占CPU。運行,控制臺打印如下:
最后一張票被賣出兩次,系統(tǒng)不可靠。第十六頁,共四十五頁。更為嚴(yán)重的是,該問題的出現(xiàn)很具有隨機(jī)性。比如,有些項目在實驗室運行階段沒有問題,因為哪個線程搶占CPU,是由操作系統(tǒng)決定的,用戶并沒有權(quán)利干涉,也無法預(yù)測,所以,項目可能在商業(yè)運行階段出現(xiàn)了問題,等到維護(hù)人員去查問題的時候,由于問題出現(xiàn)的隨機(jī)性,問題可能就不出現(xiàn)了。這種工作往往給維護(hù)帶來了巨大的代價。以上案例是多個線程消費有限資源的情況,該情況下還有很多其他案例,如:多個線程,向有限空間寫數(shù)據(jù)時:線程1寫完數(shù)據(jù),空間滿了,但沒來得及告訴系統(tǒng);此時另一個線程搶占CPU,也來寫,不知道空間已滿,造成溢出。第十七頁,共四十五頁。3.2.3解決方案怎樣解決這個問題?很簡單,就是讓一個線程賣票時其他線程不能搶占CPU。根據(jù)定義,實際上相當(dāng)于要實現(xiàn)線程的同步,通俗地講,可以給共享資源(在本例中為票)加一把鎖,這把鎖只有一把鑰匙。哪個線程獲取了這把鑰匙,才有權(quán)利訪問該共享資源。有一種比較直觀的方法,可以在共享資源(如“票”)每一個對象內(nèi)部都增加一個新成員,標(biāo)識“票”是否正在被賣中,其他線程訪問時,必須檢查這個標(biāo)識,如果這個標(biāo)識確定票正在被賣中,線程不能搶占CPU。這種設(shè)計理論上當(dāng)然也是可行,但由于線程同步的情況并不是很普遍,僅僅為了這種小概率事件,在所有對象內(nèi)部都開辟另一個成員空間,帶來極大的空間浪費,增加了編程難度,所以,一般不采用這種方法?,F(xiàn)代的編程語言的設(shè)計思路都是把同步標(biāo)識加在代碼段上,確切的說,是把同步標(biāo)識放在“訪問共享資源(如賣票)的代碼段”上。第十八頁,共四十五頁。不同語言中,同步代碼段的實現(xiàn)模型類似,只是表達(dá)方式有些不同。這里以Java語言為例,在Java語言中,synchronized關(guān)鍵字可以解決這個問題,整個語法形式表現(xiàn)為:注意,synchronized后的“同步鎖對象”,必須是可以被各個線程共享的,如this、某個全局標(biāo)量等。不能是一個局部變量。其原理為:當(dāng)某一線程運行同步代碼段時,在“同步鎖對象”上置一標(biāo)記,運行完這段代碼,標(biāo)記消除。其他線程要想搶占CPU運行這段代碼,必須在“同步鎖對象”上先檢查該標(biāo)記,只有標(biāo)記處于消除狀態(tài),才能搶占CPU。在上面的例子中,this是一個“同步鎖對象”。synchronized(同步鎖對象){//訪問共享資源,需要同步的代碼段} 第十九頁,共四十五頁。因此,在上面的案例中,可以將將賣票的代碼用synchronized代碼塊包圍起來,“同步鎖對象”取this。如代碼P03_05.java所示。運行,可以得到如下效果。
第二十頁,共四十五頁。這說明程序運行完全正常。從以上代碼可以看出,該方法的本質(zhì)是將需要獨占CPU的代碼用synchronized(this)包圍起來。如前所述,一個線程進(jìn)入這段代碼之后,就在this上加了一個標(biāo)記,直到該線程將這段代碼運行完畢,才釋放這個標(biāo)記。如果其他線程想要搶占CPU,先要檢查this上是否有這個標(biāo)記。若有,就必須等待。但是可以看出,該代碼實際上運行較慢,因為一個線程的運行,必須等待另一個線程將同步代碼段運行完畢。因此,從性能上講,線程同步是非常耗費資源的一種操作。我們要盡量控制線程同步的代碼段范圍,理論上說,同步的代碼段范圍越小,段數(shù)越少越好,因此在某些情況下,推薦將小的同步代碼段合并為大的同步代碼段。第二十一頁,共四十五頁。實際上,在Java內(nèi),還可以直接把synchronized關(guān)鍵字直接加在函數(shù)的定義上,這也是一種可以推薦的方法。不過,值得一提的是,如果不能確定整個函數(shù)都需要同步,那就要盡量避免直接把synchronized加在函數(shù)定義上的做法。如前所述,要控制同步粒度,同步的代碼段越小越好,synchronized控制的范圍越小越好,否則造成不必要的系統(tǒng)開銷。所以,在實際開發(fā)的過程中,要十分小心,因為過多的線程等待可能造成系統(tǒng)性能的下降,甚至造成死鎖。第二十二頁,共四十五頁。3.3線程協(xié)作安全第二十三頁,共四十五頁。3.3.1線程協(xié)作
有些情況下,多個線程合作完成一件事情的幾個步驟,此時線程之間實現(xiàn)了協(xié)作。如一個工作需要若干個步驟,各個步驟都比較耗時,不能因為它們的運行,影響程序的運行效果,最好的方法就是將各步用線程實現(xiàn)。但是,由于線程隨時都有可能搶占CPU,可能在前面一個步驟沒有完成時,后面的步驟線程就已經(jīng)運行,該安全隱患造成系統(tǒng)得不到正確結(jié)果。第二十四頁,共四十五頁。3.3.2案例分析給出一個案例:線程1負(fù)責(zé)完成一個復(fù)雜運算(比較耗時),線程2負(fù)責(zé)得到結(jié)果,并將結(jié)果進(jìn)行下一步處理。如:某個科學(xué)計算系統(tǒng)中,線程1負(fù)責(zé)計算1-1000各個數(shù)字的和(暫且認(rèn)為它非常耗時),線程2負(fù)責(zé)得到這個結(jié)果并且寫入數(shù)據(jù)庫。讀者首先想到的是將耗時的計算放入線程。這是正確的想法。首先用傳統(tǒng)線程方法來編寫這段代碼,代碼如P03_06.java所示。第二十五頁,共四十五頁。該程序貌似沒有問題,也能夠打印正確結(jié)果,但是和上一節(jié)的例子一樣,它也是很不安全的,這種不安全性也很難發(fā)現(xiàn),也會給項目后期維護(hù)帶來巨大的代價。該程序的安全隱患在哪里呢?觀察cal()函數(shù)中的代碼,當(dāng)線程th1運行后,線程th2運行,此時,線程th2隨時可能搶占CPU,而不一定要等線程th1運行完畢。當(dāng)然,在上面的例子中,可能因為線程th1運行較快,th2在它運行的過程中沒有搶占CPU,“碰巧”得到了正確結(jié)果,但是如果讓線程th2搶占CPU,這樣,系統(tǒng)可能得不到正確結(jié)果。為了解釋這個問題,將P03_06.java的代碼改為P03_07.java第二十六頁,共四十五頁。該代碼中,增加了一行:程序休眠1毫秒,讓另一個線程來搶占CPU。運行,控制臺打印如下:很顯然,這個結(jié)果不是我們所需要的。那為什么sum得到的結(jié)果為1呢?很明顯,線程th1的start函數(shù)運行時,相當(dāng)于讓求和過程以多線程形式運行,在它“休眠”之際,th2就搶占了CPU,在求和還沒開始做或只完成一部分時就打印sum,導(dǎo)致得到不正常結(jié)果。第二十七頁,共四十五頁。3.3.3解決方案怎樣解決?顯而易見,方法是:在運行一個線程時,命令其他線程等待該線程運行完畢,才能搶占CPU進(jìn)行運行。對于該問題,不同語言解決方法類似。以Java語言為例,在Java語言中,線程的join()方法可以解決這個問題。見代碼P03_08.java運行正常。實際上,該程序相當(dāng)于摒棄了“線程就是為了程序看起來同時做好幾件事情”的思想,將并發(fā)程序又變成了順序的,如果線程th1沒有運行完畢的話,程序會在th.join()處堵塞。如果cal()函數(shù)耗時較長,程序?qū)⒁恢钡却?。一般的方法是,可以將該工作放在另一個線程中,這樣,既不會堵塞主程序,又能夠保證數(shù)據(jù)安全性。見代碼P03_09.java第二十八頁,共四十五頁。3.4線程死鎖安全第二十九頁,共四十五頁。3.4.1線程死鎖死鎖(DeadLock),是指兩個或兩個以上的線程在執(zhí)行過程中,因爭奪資源而造成的一種互相等待的現(xiàn)象。此時稱系統(tǒng)處于死鎖狀態(tài),這些永遠(yuǎn)在互相等待的線程稱為死鎖線程。產(chǎn)生死鎖的四個必要條件是:互斥條件:資源每次只能被一個線程使用。如前面的“線程同步代碼段”,就是只能被一個線程使用的典型資源;請求與保持條件:一個線程請求資源,但因為某種原因,該資源無法分配給它,于是該線程阻塞,此時,它對已獲得的資源保持不放;不剝奪條件:進(jìn)程已獲得的資源,在未使用完之前,不管其是否阻塞,無法強(qiáng)行剝奪;循環(huán)等待條件:若干進(jìn)程之間互相等待,形成一種頭尾相接的循環(huán)等待資源關(guān)系。這四個條件是死鎖的必要條件,只要系統(tǒng)發(fā)生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發(fā)生死鎖。第三十頁,共四十五頁。3.4.2案例分析以Java語言為例,死鎖一般來源于代碼段的同步,當(dāng)一段同步代碼被某線程運行時,其他線程可能進(jìn)入堵塞狀態(tài)(無法搶占CPU),而剛好在該線程中,訪問了某個對象,此時,除非同步鎖定被解除,否則其他線程就不能訪問那個對象。這可以稱為“線程正在等待一個對象資源”。如果出現(xiàn)一種極端情況,一個線程等候另一個對象,而另一個對象又在等候下一個對象,以此類推。這個“等候鏈”如果進(jìn)入封閉狀態(tài),也就是說,最后那個對象等候的是第一個對象,此時,所有線程都會陷入無休止的相互等待狀態(tài),造成死鎖。盡管這種情況并非經(jīng)常出現(xiàn),但一旦碰到,程序的調(diào)試將變得異常艱難。在這里給出一個死鎖的案例,如代碼P03_10.java第三十一頁,共四十五頁。這段程序也貌似沒有問題。但是和上一節(jié)的例子一樣,它也是很不安全的,這種不安全性也很難發(fā)現(xiàn)。觀察run()函數(shù)中的代碼,當(dāng)th1運行后,進(jìn)入代碼段1,鎖定了S1,如果此時th2運行,搶占CPU,進(jìn)入代碼段3,鎖定S2,那么th1就無法運行代碼段2,但是又沒有釋放S1,此時,th2也就不能運行代碼段4。造成互相等待。為了模擬這個過程,我們在程序中增加讓其休眠的代碼,好讓另一個線程來搶占CPU。將P03_10.java的代碼改為P03_11.java該代碼中,增加了一行:程序休眠1000毫秒,讓另一個線程來搶占CPU。運行,控制臺打印如下:
兩個線程陷入無休止的等待。其原因是,線程th1進(jìn)入代碼段1后,線程2搶占CPU,鎖定了S2,而線程th1對S1的鎖定又沒有解除,造成線程th2無法運行下去,當(dāng)然,由于線程th2鎖定了S2,線程th1也無法運行下去。死鎖是一個很重要的問題,它能導(dǎo)致整個應(yīng)用程序慢慢終止,尤其是當(dāng)開發(fā)人員不熟悉如何分析死鎖環(huán)境的時候,還很難被分離和修復(fù)。
第三十二頁,共四十五頁。3.4.3解決方案就語言本身來說,尚未直接提供防止死鎖的幫助措施,需要我們通過謹(jǐn)慎的設(shè)計來避免。一般情況下,我們主要是針對死鎖產(chǎn)生的四個必要條件來進(jìn)行破壞,用以避免和預(yù)防死鎖。在系統(tǒng)設(shè)計、線程開發(fā)等方面,注意如何不讓這四個必要條件成立,如何確定資源的合理分配算法,避免線程永久占據(jù)系統(tǒng)資源。以Java為例,Java并不提供對死鎖的檢測機(jī)制。但可以通過javathreaddump來進(jìn)行判斷:一般情況下,當(dāng)死鎖發(fā)生時,Java虛擬機(jī)處于掛起狀態(tài),threaddump可以給出靜態(tài)穩(wěn)定的信息,從操作系統(tǒng)上觀察,虛擬機(jī)的CPU占用率為零,這時可以收集threaddump,查找"waitingformonitorentry"的線程,如果大量thread都在等待給同一個地址上鎖,說明很可能死鎖發(fā)生了。解決死鎖沒有簡單的方法,這是因為線程產(chǎn)生死鎖都各有各的原因,而且往往具有很高的負(fù)載。從技術(shù)上講,可以用如下方法來進(jìn)行死鎖排除:可以撤消陷于死鎖的全部線程??梢灾饌€撤消陷于死鎖的進(jìn)程,直到死鎖不存在。從陷于死鎖的線程中逐個強(qiáng)迫放棄所占用的資源,直至死鎖消失。提示:關(guān)于死鎖的檢測與解除,有很多重要算法,如資源分配算法、銀行家算法等。在操作系統(tǒng)的一些參考資料中應(yīng)該可以進(jìn)行足夠了解。第三十三頁,共四十五頁。很多軟件產(chǎn)品內(nèi)置了死鎖解決策略,可做參考。如:數(shù)據(jù)庫死鎖。一個連接占用了另一個連接所需的數(shù)據(jù)庫鎖,它可能阻塞另一個連接。如果兩個或兩個以上的連接相互阻塞,產(chǎn)生死鎖。該情況下,一般會強(qiáng)制銷毀一個連接(通常是使用最少的連接),并回滾其事務(wù)。這將釋放所有與已經(jīng)結(jié)束的事務(wù)相關(guān)聯(lián)的鎖,至少允許其他連接中有一個可以獲取它們正在被阻塞的鎖。資源池耗盡死鎖。資源池太小,而每個線程需要的資源超過了池中的可用資源,產(chǎn)生死鎖。此時可以增加連接池的大小或者重構(gòu)代碼,以便單個線程不需要同時使用很多資源。第三十四頁,共四十五頁。3.5線程控制安全第三十五頁,共四十五頁。3.5.1安全隱患線程控制主要是對線程生命周期的一些操作,如暫停、繼續(xù)、消亡等。本節(jié)以Java語言為例,講解線程控制中的一些安全問題。Java中提供了對線程生命周期進(jìn)行控制的函數(shù):stop():停止線程;suspend():暫停線程的運行;resume():繼續(xù)線程的運行:destroy():讓線程銷毀;等等。線程生命周期中的安全問題主要體現(xiàn)在:線程暫?;蛘呓K止時,可能對某些資源的鎖并沒有釋放,它所保持的任何資源都會保持鎖定狀態(tài);線程暫停之后,我們無法預(yù)計它什么時候會繼續(xù)(一般和用戶操作有關(guān)),如果對某個資源的鎖長期被保持,其他線程在任何時候都無法再次訪問該資源,極有可能造成死鎖。針對這個問題,為減少出現(xiàn)死鎖的可能,Java1.2中,將Thread的stop(),suspend(),resume()以及destroy()方法定義為“已過時”方法,不再推薦使用。第三十六頁,共四十五頁。3.5.2案例分析如前所述,線程的暫停和繼續(xù),早期采用suspend()和resume()方法,但是容易發(fā)生死鎖。以線程暫停為例,調(diào)用suspend()的時候,目標(biāo)線程會停下來,但卻仍然持有在這之前獲得的鎖定。此時,其他任何線程都不能訪問鎖定的資源,除非被“掛起”的線程恢復(fù)運行。如果它們想恢復(fù)目標(biāo)線程,同時又試圖使用任何一個鎖定的資源,就會造成死鎖。下面給出一個案例,來說明這個問題。屏幕上不斷打印歡迎信息,點擊按鈕,打印工作暫停;再點擊,繼續(xù)打印。傳統(tǒng)代碼如P03_12.java如果點擊“暫停”按鈕,則暫停打印;再點擊,繼續(xù)打印。如上所述,該代碼實際上在事件響應(yīng)中用suspend()和resume()來控制線程的暫停和繼續(xù),是不安全的。第三十七頁,共四十五頁。3.5.3解決方案解決該問題,常見的方法有如下幾種:1:當(dāng)需要暫停時,干脆讓線程的run()方法結(jié)束運行以釋放資源(實際上就是讓該線程永久結(jié)束);繼續(xù)時,新開辟一個線程繼續(xù)工作。怎樣讓run()方法結(jié)束呢?一般可用一個標(biāo)志告訴線程什么時候通過退出自己的run()方法來中止自己的執(zhí)行。2:將線程暫?;蚶^續(xù),不使用suspend()和resume(),可在Thread類中置入一個標(biāo)志,指出線程應(yīng)該活動還是掛起。若標(biāo)志指出線程應(yīng)該掛起,便用wait()命其進(jìn)入等待狀態(tài)。若標(biāo)志指出線程應(yīng)當(dāng)恢復(fù),則用一個notify()重新啟動線程。3:不推薦使用stop()來終止阻塞的線程,而應(yīng)換用由Thread提供的interrupt()方法,以便中止并退出堵塞的代碼。第三十八頁,共四十五頁。3.6進(jìn)程安全第三十九頁,共四十五頁。3.6.1進(jìn)程概述進(jìn)程是一個執(zhí)行中的程序,對每一個進(jìn)程來說,都有自己獨立的一片內(nèi)存空間和一組系統(tǒng)資源。進(jìn)程由進(jìn)程控制塊、程序段、數(shù)據(jù)段三部分組成。在進(jìn)程概念中,每一個進(jìn)程的內(nèi)部數(shù)據(jù)和狀態(tài)都是完全獨立的。一個進(jìn)程可以包含若干線程,線程可以幫助應(yīng)用程序同時做幾件事(比如一個線程向磁盤寫入文件,另一個則接收用戶的按鍵操作并及時做出反應(yīng),互相不干擾)。進(jìn)程也有運行、阻塞、就緒三種狀態(tài),并隨一定條件而相互轉(zhuǎn)化。
第四十頁,共四十五頁。3.6.2進(jìn)程安全問題由于進(jìn)程的獨立性,從應(yīng)用的角度講,進(jìn)程安全比線程安全更受重視,一般針對已有的進(jìn)程進(jìn)行安全方面的控制。如:在系統(tǒng)安全中發(fā)現(xiàn)并清除病毒進(jìn)程;在網(wǎng)絡(luò)應(yīng)用中,優(yōu)化守護(hù)進(jìn)程或端口掃描進(jìn)程;等等。不過,從開發(fā)者(編程)的角度,進(jìn)程的安全所需要考慮的問題和線程類似,但由于線程能夠共享進(jìn)程的資源,所以線程安全一般考慮的問題比進(jìn)程安全多。不過,對于開發(fā)多個進(jìn)程能夠運行的系統(tǒng)軟件(如操作系統(tǒng)
溫馨提示
- 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)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 家紡企業(yè)社會責(zé)任報告編寫考核試卷
- 面門出租合同范本
- 電影合同范本4篇
- 煤炭居間費合同范本
- 小學(xué)生頒獎視頻模板課件
- 基于大數(shù)據(jù)的智能種植管理平臺構(gòu)建
- 人才派遣與招聘協(xié)議
- 日常照護(hù)培訓(xùn)課件
- 農(nóng)業(yè)生產(chǎn)安全防范指南
- 互聯(lián)網(wǎng)行業(yè)數(shù)據(jù)安全防護(hù)策略
- 關(guān)愛婦女防治兩癌講座課件
- DL∕T 584-2017 3kV~110kV電網(wǎng)繼電保護(hù)裝置運行整定規(guī)程
- (正式版)FZ∕T 80018-2024 服裝 防靜電性能要求及試驗方法
- 玻璃體腔注藥及圍注射期管理
- 北師大版八年級下冊生物教案全冊
- 技術(shù)學(xué)院各部門廉政風(fēng)險點、防控措施匯編
- JGJ133-2001 金屬與石材幕墻工程技術(shù)規(guī)范
- 穩(wěn)定性冠心病診斷與治療指南
- DL-T5704-2014火力發(fā)電廠熱力設(shè)備及管道保溫防腐施工質(zhì)量驗收規(guī)程
- (高清版)JGT 225-2020 預(yù)應(yīng)力混凝土用金屬波紋管
- JT-T-610-2004公路隧道火災(zāi)報警系統(tǒng)技術(shù)條件
評論
0/150
提交評論