hyljava

          線程和進程

          線程和進程

          一,線程的一些基本知識。
          進程與線程
          所有的操作系統都支持同時運行多個任務,一個任務通常就是一個程序,每個運行中就是一個進程,當一個程序運行時,內部可能包含了多個順序執行流,每個順序執行流就是一個線程。

          進程(process)
          當一個程序進入內存運行即變成一個進程,進程處于運行過程中的程序,并且具有一定的獨立功能,進程是系統進行資源分配和調用的獨立單位,進程切換開銷大。

          多進程
          在操作系統中,能同時運行多個任務程序。

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

          注:
          對于一個CPU而言,它在某個時間點上只能執行一個程序,就是說只能運行一個進程。CPU不斷在這些進程之間輪回切換,CPU的執行速度相對于我們的感覺太快,我們感覺不到,所以CPU在多個進程之間輪回執行,但我們人類感覺好像多個進程同時執行。

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

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

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

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

          當操作系統創建一個進程時,該進程必須分配獨立的內存空間,分配大量相關資料,但創建一個線程簡單的多,因此使用多線程來實現并發比使用多進程來實現并發的性能要高得多。

          多線程的優點
          1
          ,進程之間不能共享內存,但線程之間共享內存非常容易。
          2
          ,系統創建進程需要為該進程重新分配系統資源,但創建線程代價要小的多,因此使用多線程來實現多個任務并發比多進程要效率高。
          3
          Java語言中內置多線程功能的支持,而不是單純的作為底層的操作系統的調動方式,從而簡化了Java的多線程編程。

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

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

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

          在指定的毫秒內讓當前正在執行的線程休眠.

          1,實現Runable接口的實現類,并重寫該接口的run方法,該run方法的方法體同樣是該線程的執行體。
          2
          ,創建Runable實現類的實例,并以此實例作為Thread類的目標來創建Thread類的目標創建Thread對象,該Thread對象才是真正的線程對象。

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

          實現Runable接口的優點:
          線程只是實現了Runable接口,還可以繼承其他的類,在這種方式下,可以多個線程共享同一個目標(target)對象,所以非常適合多個線程來處理同一份資源的情況,從而可以將CPU代碼和數據分開,形成清晰的模型,體現了面向對象的思想。
          實現Runable接口的缺點:
          編程稍微復雜,如果需要訪問當前線程,必須使用Thread.currentThread方法。

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

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

          當線程對象調用了start方法之后,該線程處于就緒狀態,JVM會為創建方法調用棧和線程計數器處于這個狀態中的線程,并沒有開始運行,它只是表示該線程可以運行了,至于該線程何時開始運行,取決于JVM里線程調度器的調度。

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

          注:
          阻塞狀態也叫不可運行狀態
          調用yield方法可以讓當前運行的線程轉入就緒狀態。

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

          isAlive方法
          測試某條線程是否已經死亡,當線程處于就緒,運行,阻塞三種狀態時,該方法返回true,當該線程處于創建,死亡兩種狀態時,該方法返回false

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

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

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


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

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

          sleep(long millis)方法(線程睡眠)
          讓當前正在執行的線程暫停并進入阻塞狀態,該方法受到系統計時器和線程調度器的精度和準確度的影響。

          注:
          當前線程調用sleep方法,進入阻塞狀態后,在sleep時間段內,該線程不會獲得執行的機會,即使系統中沒有其他可運行的線程,處于sleep時間段里的線程也不會運行。因此sleep常用來暫停程序的執行,


          yield()
          方法(線程讓步)
          yield
          方法和sleep有點相似的方法,讓當前正在執行的線程暫停,但它不會阻塞該線程,它只是將該線程轉入就緒狀態,yield方法只是讓當前線程暫停一下,讓系統的線程調度器從新調度一次,當某個線程調用了yield方法暫停之后,只有優先級與當前線程相同,或者優先級比當前線程更高的就緒狀態的線程才會獲得執行的機會


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


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


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


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

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

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

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

           void interrupt()
                   
          中斷線程。

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

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

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

          void run()
                   
          如果該線程是使用獨立的 Runnable 運行對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執行任何操作并返回。

           void setDaemon(boolean on)
                   
          將該線程標記為守護線程或用戶線程。

           void start()
                   
          使該線程開始執行;Java 虛擬機調用該線程的 run 方法。

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


          ThreadGroup

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

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

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

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


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

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

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

           

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

          評論

          # re: 線程和進程[未登錄] 2013-05-09 10:07 AA

          好  回復  更多評論   

          主站蜘蛛池模板: 福泉市| 渝中区| 柳州市| 高陵县| 化州市| 闵行区| 洪雅县| 赞皇县| 屯留县| 新乡县| 都匀市| 郸城县| 海盐县| 温州市| 涞源县| 南皮县| 陵川县| 巴东县| 虹口区| 黔西县| 太湖县| 台江县| 宁陵县| 明溪县| 门头沟区| 宜昌市| 馆陶县| 柳林县| 嵊泗县| 沂南县| 台南县| 含山县| 宣汉县| 若尔盖县| 久治县| 东光县| 芷江| 阳山县| 洱源县| 广水市| 托克托县|