hyljava

          線程和進(jìn)程

          線程和進(jìn)程

          一,線程的一些基本知識。
          進(jìn)程與線程
          所有的操作系統(tǒng)都支持同時運(yùn)行多個任務(wù),一個任務(wù)通常就是一個程序,每個運(yùn)行中就是一個進(jìn)程,當(dāng)一個程序運(yùn)行時,內(nèi)部可能包含了多個順序執(zhí)行流,每個順序執(zhí)行流就是一個線程。

          進(jìn)程(process)
          當(dāng)一個程序進(jìn)入內(nèi)存運(yùn)行即變成一個進(jìn)程,進(jìn)程處于運(yùn)行過程中的程序,并且具有一定的獨立功能,進(jìn)程是系統(tǒng)進(jìn)行資源分配和調(diào)用的獨立單位,進(jìn)程切換開銷大。

          多進(jìn)程
          在操作系統(tǒng)中,能同時運(yùn)行多個任務(wù)程序。

          進(jìn)程包含三大特征
          1
          ,獨立性:
          進(jìn)程是系統(tǒng)中獨立存在的實體,它可以擁有自己獨立的資源,每一個進(jìn)程都擁有自己私有的地址空間,沒有經(jīng)過進(jìn)程本身允許的情況下,一個用戶不可以直接訪問其他進(jìn)程的地址空間。
          2
          ,動態(tài)性:
          進(jìn)程與程序的區(qū)別在于程序只是個靜態(tài)的指定集合,而進(jìn)程是一個正在系統(tǒng)中活動的指定集合,在進(jìn)程中加入了時間的概念,進(jìn)程具有自己的生命周期和各種不同的狀態(tài),這些狀態(tài)在程序中是不具備的。
          3
          ,并發(fā)性:
          多個線程可以在單個處理器是并發(fā)執(zhí)行多個進(jìn)程,進(jìn)程之間,不會互相影響。

          注:
          對于一個CPU而言,它在某個時間點上只能執(zhí)行一個程序,就是說只能運(yùn)行一個進(jìn)程。CPU不斷在這些進(jìn)程之間輪回切換,CPU的執(zhí)行速度相對于我們的感覺太快,我們感覺不到,所以CPU在多個進(jìn)程之間輪回執(zhí)行,但我們?nèi)祟惛杏X好像多個進(jìn)程同時執(zhí)行。

          線程(Thread)
          線程被稱為輕量級的進(jìn)程,線程是進(jìn)程的執(zhí)行單元,就像進(jìn)程在操作系統(tǒng)中的地位一樣。線程在程序中是獨立的,并發(fā)的執(zhí)行的流。當(dāng)進(jìn)程被初始化后,主線程就被創(chuàng)建了,一般的應(yīng)用程序來說,通常僅要求有一個主線程,但我們也可以在該進(jìn)程內(nèi)創(chuàng)建多條順序執(zhí)行流,這些順序執(zhí)行流就是線程,每條線程是相互獨立的。

          注:
          總而言之,一個程序運(yùn)行后,至少有一個進(jìn)程,一個進(jìn)程里可以包含多個線程,但至少要包含一個線程。

          多線程(multithreading)
          在同一個應(yīng)用程序中,有多個順序執(zhí)行流同時執(zhí)行。

          線程比進(jìn)程具有更高的性能,這是由于同一個進(jìn)程中的線程都有共性,多個線程將共享同一個進(jìn)程的虛擬空間,-線程共享的環(huán)境包括進(jìn)程代碼段,進(jìn)程的公有數(shù)據(jù)等,利用這些共享的數(shù)據(jù),線程很容易實現(xiàn)相互之間的通信。

          當(dāng)操作系統(tǒng)創(chuàng)建一個進(jìn)程時,該進(jìn)程必須分配獨立的內(nèi)存空間,分配大量相關(guān)資料,但創(chuàng)建一個線程簡單的多,因此使用多線程來實現(xiàn)并發(fā)比使用多進(jìn)程來實現(xiàn)并發(fā)的性能要高得多。

          多線程的優(yōu)點
          1
          ,進(jìn)程之間不能共享內(nèi)存,但線程之間共享內(nèi)存非常容易。
          2
          ,系統(tǒng)創(chuàng)建進(jìn)程需要為該進(jìn)程重新分配系統(tǒng)資源,但創(chuàng)建線程代價要小的多,因此使用多線程來實現(xiàn)多個任務(wù)并發(fā)比多進(jìn)程要效率高。
          3
          Java語言中內(nèi)置多線程功能的支持,而不是單純的作為底層的操作系統(tǒng)的調(diào)動方式,從而簡化了Java的多線程編程。

          二,線程的啟動和創(chuàng)建
          Thread
          (Java.lang.Thread)
          Java語言中Thread類代表線程,所有的線程對象都必須是Thread類或其子類的實例。每條線程的作用是完成一定的任務(wù),實際上就是執(zhí)行一段程序流,也叫一段順序執(zhí)行的代碼,Java使用run方法來封裝這樣一段程序流。

          繼承Thread類創(chuàng)建和啟動線程
          1
          ,定義Thread類的子類,并重寫該類的run方法,該run方法的方法體就是代表了線程需要完成的任務(wù),run方法也被稱為線程執(zhí)行體。
          2
          ,創(chuàng)建Thread類子類的實例,即創(chuàng)建了線程的對象。
          3
          ,用線程對象的start方法來啟動該線程。

          start()方法
          使該線程開始執(zhí)行,Java虛擬機(jī)調(diào)用該線程的run方法。
          getName()
          方法
          返回該線程的名稱
          setName(String name)
          方法
          修改該線程的名稱
          interrupt();
          中斷線程
          sleep(long millis)

          在指定的毫秒內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠.

          1,實現(xiàn)Runable接口的實現(xiàn)類,并重寫該接口的run方法,該run方法的方法體同樣是該線程的執(zhí)行體。
          2
          ,創(chuàng)建Runable實現(xiàn)類的實例,并以此實例作為Thread類的目標(biāo)來創(chuàng)建Thread類的目標(biāo)創(chuàng)建Thread對象,該Thread對象才是真正的線程對象。

          Thread類和Runable接口創(chuàng)建線程的對比
          繼承Thread類方式的多線程的優(yōu)點:
          編寫簡單,如果訪問當(dāng)前線程,無需使用Thread.currentThread方法,直接使用this,即可獲得當(dāng)前線程。
          繼承Thread類方式的多線程缺點:
          因為線程已經(jīng)繼承了Thread類,所以不能再繼承其他的類。

          實現(xiàn)Runable接口的優(yōu)點:
          線程只是實現(xiàn)了Runable接口,還可以繼承其他的類,在這種方式下,可以多個線程共享同一個目標(biāo)(target)對象,所以非常適合多個線程來處理同一份資源的情況,從而可以將CPU代碼和數(shù)據(jù)分開,形成清晰的模型,體現(xiàn)了面向?qū)ο蟮乃枷搿?/span>
          實現(xiàn)Runable接口的缺點:
          編程稍微復(fù)雜,如果需要訪問當(dāng)前線程,必須使用Thread.currentThread方法。

          三,線程的生命周期
          當(dāng)線程被創(chuàng)建并啟動以后,它既不是一啟動就進(jìn)入了執(zhí)行的狀態(tài),也不是一直處于執(zhí)行狀態(tài),在線程的生命周期里,它要經(jīng)過新建,就緒,運(yùn)行,阻塞,死亡五種狀態(tài)。尤其是當(dāng)線程啟動以后,它不能一直霸占著CPU獨立運(yùn)行,所以CPU多條線程之間切換,于是線程狀態(tài)也會多次在運(yùn)行和阻塞之間切換。

          新建或就緒狀態(tài)
          啟動線程使用start方法,而不是run方法,永遠(yuǎn)不用調(diào)用線程對象的run方法,調(diào)用start方法來啟動線程系統(tǒng)會把該run方法當(dāng)成線程執(zhí)行體來處理。但如果直接調(diào)用線程對象的run方法,則run方法立即會被執(zhí)行,而且在run方法返回之前其他線程無法并發(fā)執(zhí)行,也就是說系統(tǒng)吧線程對象當(dāng)成一個普通的對象,而run方法也是一個普通方法,而不是線程執(zhí)行體。

          當(dāng)線程對象調(diào)用了start方法之后,該線程處于就緒狀態(tài),JVM會為創(chuàng)建方法調(diào)用棧和線程計數(shù)器處于這個狀態(tài)中的線程,并沒有開始運(yùn)行,它只是表示該線程可以運(yùn)行了,至于該線程何時開始運(yùn)行,取決于JVM里線程調(diào)度器的調(diào)度。

          運(yùn)行和阻塞狀態(tài)
          如果處于就緒狀態(tài)的線程獲得了CPU資源,開始執(zhí)行run方法的執(zhí)行體,則該線程處于運(yùn)行狀態(tài),當(dāng)一條線程開始運(yùn)行后,它不可能一直處于運(yùn)行狀態(tài),線程在運(yùn)行的過程中,需要被中斷,目的是使其他線程獲得執(zhí)行的機(jī)會,當(dāng)發(fā)生以下情況下,線程將會進(jìn)入阻塞狀態(tài);
          1,
          線程調(diào)用sleep方法主動放棄所占有的CPU資源。
          2
          ,線程調(diào)用一個阻塞式IO方法,該方法返回之前該線程被阻塞。
          3
          ,線程試圖獲得一個同步監(jiān)視器,但該同步監(jiān)視器正被其他線程所占據(jù)。
          4
          ,線程在等待某個通知(ntify,ntifyAll方法 Objiet類里)
          5
          ,程序調(diào)用了線程的suspend方法,將線程掛起暫停),不過這個方法容易導(dǎo)致死鎖,所以程序盡量避免該方法。
          線程重新進(jìn)入就緒狀態(tài)有以下情況:
          1
          ,調(diào)用sleep方法的線程經(jīng)過指定的時間。
          2
          ,線程調(diào)用阻塞式IO方法已經(jīng)返回。
          3
          ,線程成功的獲得了試圖取得同步監(jiān)視器。
          4
          ,線程正在等待某個通知,其他線程發(fā)出了通知。
          5
          ,處于掛起狀態(tài)的線程被調(diào)用了resume方法恢復(fù)。

          注:
          阻塞狀態(tài)也叫不可運(yùn)行狀態(tài)
          調(diào)用yield方法可以讓當(dāng)前運(yùn)行的線程轉(zhuǎn)入就緒狀態(tài)。

          線程會在以下三種方式之一結(jié)束線程,處于死亡狀態(tài):
          1
          run方法執(zhí)行完成,線程正常結(jié)束。
          2
          ,線程拋出一個未捕獲的ExceptionError
          3
          ,直接調(diào)用線程的stop方法來結(jié)束該線程,該方法容易導(dǎo)致死鎖,通常不推薦用。

          isAlive方法
          測試某條線程是否已經(jīng)死亡,當(dāng)線程處于就緒,運(yùn)行,阻塞三種狀態(tài)時,該方法返回true,當(dāng)該線程處于創(chuàng)建,死亡兩種狀態(tài)時,該方法返回false

          注:
          不要試圖對一個已經(jīng)死亡的線程調(diào)用start方法,使它重新啟動,該線程將不可再次作為線程執(zhí)行,它會拋出IllegaThreadStateException異常。

          不要讓處于死亡狀態(tài)的線程調(diào)用start方法,程序只能對新建狀態(tài)的線程調(diào)用start方法,對新建狀態(tài)的線程兩次調(diào)用start方法也是錯誤的。

          join()方法
          等待被join的線程執(zhí)行完成。
          join(long millis)
          方法
          join的新車的時間最長為minllis毫秒,如果在millis毫秒內(nèi)被join的線程還沒有執(zhí)行結(jié)束,則不再等待。
          join(long millis ,int nanos)
          方法
          等待被join的時機(jī)最長為millis毫秒加nanos納秒。


          setPriority()
          和方法:
          來設(shè)值和取值,
          返回線程的優(yōu)先級,其中setPriority可以是個整數(shù),范圍是一到十之間,也可以是MAX_PRIORITY MIN_PRIORITY NORM_PRIORITY 三個靜態(tài)常量。
          getPriority()
          方法
          返回線程的優(yōu)先級。每個線程執(zhí)行時,都具有一定的優(yōu)先級,優(yōu)先級高的線程獲得較多的執(zhí)行機(jī)會,而優(yōu)先級低的線程則獲得較小的執(zhí)行機(jī)會。

          后臺線程(DaemonThread)
          有一種線程它是在后臺運(yùn)行的,它的任務(wù)是為其他線程提供服務(wù),這種線程稱為后臺線程,又稱為守護(hù)線程,又稱為精靈線程。JVM的垃圾回收線程就是典型的后臺線程。后臺線程有個特征:如果所有的前臺線程都死亡,后臺線程會自動死亡。調(diào)用Thread對象的setDaemon(blooean on)方法(參數(shù)傳true),可將指定線程設(shè)置為后臺線程,isDaemon()判斷該線程是否為后臺線程,如果該線程是守護(hù)線程,則返回 true;否則返回 false

          sleep(long millis)方法(線程睡眠)
          讓當(dāng)前正在執(zhí)行的線程暫停并進(jìn)入阻塞狀態(tài),該方法受到系統(tǒng)計時器和線程調(diào)度器的精度和準(zhǔn)確度的影響。

          注:
          當(dāng)前線程調(diào)用sleep方法,進(jìn)入阻塞狀態(tài)后,在sleep時間段內(nèi),該線程不會獲得執(zhí)行的機(jī)會,即使系統(tǒng)中沒有其他可運(yùn)行的線程,處于sleep時間段里的線程也不會運(yùn)行。因此sleep常用來暫停程序的執(zhí)行,


          yield()
          方法(線程讓步)
          yield
          方法和sleep有點相似的方法,讓當(dāng)前正在執(zhí)行的線程暫停,但它不會阻塞該線程,它只是將該線程轉(zhuǎn)入就緒狀態(tài),yield方法只是讓當(dāng)前線程暫停一下,讓系統(tǒng)的線程調(diào)度器從新調(diào)度一次,當(dāng)某個線程調(diào)用了yield方法暫停之后,只有優(yōu)先級與當(dāng)前線程相同,或者優(yōu)先級比當(dāng)前線程更高的就緒狀態(tài)的線程才會獲得執(zhí)行的機(jī)會


          sleep
          方法和yield方法的區(qū)別
          1
          sleep方法暫停當(dāng)前線程后,會給其他線程執(zhí)行機(jī)會,不會理會其他線程的優(yōu)先級,但yield方法只會給優(yōu)先級相同或優(yōu)先級更高的線程執(zhí)行機(jī)會。
          2
          sleep方法會將線程轉(zhuǎn)入阻塞狀態(tài),直到經(jīng)過阻塞時間,才會轉(zhuǎn)入就緒狀態(tài),而yield方法不會將線程轉(zhuǎn)入阻塞狀態(tài),它只是強(qiáng)制當(dāng)前線程進(jìn)入就緒狀態(tài),因此完全有可能某個線程用yield方法暫停之后立即再次獲得處理器資源被執(zhí)行。
          3
          sleep方法聲明拋出 InterruptedException 異常。所有調(diào)用sleep方法時,要么撲捉該異常,要么顯示聲明拋出該異常。而yield方法則沒有聲明拋出任何異常。
          4
          sleep方法比yield方法有更好的可移植性,通常不用依靠yield方法來控制并發(fā)線程的執(zhí)行。


          interrupt()
          使該線程中斷,如果一個線程拋出異常,可以用interruptcatch里中斷該線程.


          Thread()
                   
          分配新的 Thread 對象。
          Thread(Runnable target)
                   
          分配新的 Thread 對象。
          Thread(Runnable target, String name)
                   
          分配新的 Thread 對象。
          Thread(String name) 


          static Thread currentThread()
                   
          返回對當(dāng)前正在執(zhí)行的線程對象的引用。

           String getName()
                   
          返回該線程的名稱。

           void setName(String name)
                   
          改變線程名稱,使之與參數(shù) name 相同。

           int getPriority()
                   
          返回線程的優(yōu)先級。
           void setPriority(int newPriority)
                   
          更改線程的優(yōu)先級。

           void interrupt()
                   
          中斷線程。

          boolean isAlive()
                   
          測試線程是否處于活動狀態(tài)。

           boolean isDaemon()
                   
          測試該線程是否為守護(hù)線程。

           void join()
                   
          等待該線程終止。
           void join(long millis)
                   
          等待該線程終止的時間最長為 millis 毫秒。

          void run()
                   
          如果該線程是使用獨立的 Runnable 運(yùn)行對象構(gòu)造的,則調(diào)用該 Runnable 對象的 run 方法;否則,該方法不執(zhí)行任何操作并返回。

           void setDaemon(boolean on)
                   
          將該線程標(biāo)記為守護(hù)線程或用戶線程。

           void start()
                   
          使該線程開始執(zhí)行;Java 虛擬機(jī)調(diào)用該線程的 run 方法。

          static void yield()
                   
          暫停當(dāng)前正在執(zhí)行的線程對象,并執(zhí)行其他線程。


          ThreadGroup

          ThreadGroup
          類來表示線程組,它可以對一批線程進(jìn)行分類管理。Java允許程序直接對線程組進(jìn)行控制,

           
          線程同步
          Java
          里的多線程編程常常容易突然出現(xiàn)錯誤情況,這是由于系統(tǒng)的線程調(diào)度具有一定隨機(jī)性,即使程序在運(yùn)行過程中偶爾出現(xiàn)問題,是由于我們編程不當(dāng)所引起的。當(dāng)使用多個線程來訪問同一個數(shù)據(jù)時,非常容易出現(xiàn)線程安全問題,所以我們用同步機(jī)制來解決這些問題。

          實現(xiàn)同步機(jī)制有兩個方法:
          1
          ,同步代碼塊:
          synchronized(
          同一個數(shù)據(jù)){}    同一個數(shù)據(jù):就是N條線程同時訪問一個數(shù)據(jù)
          2
          ,同步方法:
          public synchronized
          數(shù)據(jù)返回類型 方法名(){}
          就是使用 synchronized 來修飾某個方法,則該方法稱為同步方法。對于同步方法而言,無需顯示指定同步監(jiān)視器,同步方法的同步監(jiān)視器是 this 也就是該對象的本身,通過使用同步方法,可非常方便的將某類變成線程安全的類,具有如下特征:
          1
          ,該類的對象可以被多個線程安全的訪問。
          2
          ,每個線程調(diào)用該對象的任意方法之后,都將得到正確的結(jié)果。
          3
          ,每個線程調(diào)用該對象的任意方法之后,該對象狀態(tài)依然保持合理狀態(tài)。
          注:synchronized關(guān)鍵字可以修飾方法,也可以修飾代碼塊,但不能修飾構(gòu)造器,屬性等。

          實現(xiàn)同步機(jī)制注意以下幾點:   安全性高,性能低,在多線程用。性能高,安全性低,在單線程用。
          1
          ,不要對線程安全類的所有方法都進(jìn)行同步,只對那些會改變共享資源方法的進(jìn)行同步。
          2
          ,如果可變類有兩種運(yùn)行環(huán)境,當(dāng)線程環(huán)境和多線程環(huán)境則應(yīng)該為該可變類提供兩種版本:線程安全版本和線程不安全版本(沒有同步方法和同步塊)。在單線程中環(huán)境中,使用線程不安全版本以保證性能,在多線程中使用線程安全版本.


          Java.lang.object
          里的三個方法wait() notify()  notifyAll()
          wait
          方法導(dǎo)致當(dāng)前線程等待,直到其他線程調(diào)用同步監(jiān)視器的notify方法或notifyAll方法來喚醒該線程。
          wait(mills)
          方法
          都是等待指定時間后自動蘇醒,調(diào)用wait方法的當(dāng)前線程會釋放該同步監(jiān)視器的鎖定,可以不用notifynotifyAll方法把它喚醒。

          notify()
          喚醒在同步監(jiān)視器上等待的單個線程,如果所有線程都在同步監(jiān)視器上等待,則會選擇喚醒其中一個線程,選擇是任意性的,只有當(dāng)前線程放棄對該同步監(jiān)視器的鎖定后,也就是使用wait方法后,才可以執(zhí)行被喚醒的線程。

          notifyAll()方法
          喚醒在同步監(jiān)視器上等待的所有的線程。只用當(dāng)前線程放棄對該同步監(jiān)視器的鎖定后,才可以執(zhí)行被喚醒的線程

           

          posted on 2012-12-08 13:24 何云隆 閱讀(2889) 評論(1)  編輯  收藏 所屬分類: java

          評論

          # re: 線程和進(jìn)程[未登錄] 2013-05-09 10:07 AA

          好  回復(fù)  更多評論   

          主站蜘蛛池模板: 金堂县| 休宁县| 铁岭县| 恩平市| 灵丘县| 屏东县| 桂东县| 广南县| 高尔夫| 西宁市| 萍乡市| 普定县| 璧山县| 潼南县| 聊城市| 安达市| 辽阳县| 油尖旺区| 嵩明县| 恩施市| 定襄县| 遵义县| 木兰县| 萨迦县| 墨玉县| 姜堰市| 蒲城县| 黑龙江省| 宣恩县| 洪江市| 德保县| 宣武区| 凌云县| 福泉市| 澄江县| 盐池县| 合阳县| 安阳县| 恩平市| 乌拉特前旗| 康平县|