1. 程式人生 > >9--黑馬程式設計師--技術總結之多執行緒

9--黑馬程式設計師--技術總結之多執行緒

、期待與您交流! ----------------------

一.多執行緒的概念

以往開發的程式大多是單執行緒的,即一個程式只有一條從頭至尾的執行線索。然而現實世界中的很多過程都具有多條線索同時動作的特性:例如,我們可以一邊看電視,一邊活動胳膊,如果不容許這樣做,我們會感覺很難受。再如一個網路伺服器可能需要同時處理多個客戶機的請求等。
        Java的一大特性點就是內建對多執行緒的支援。多執行緒是指同時存在幾個執行體,按幾條不同的執行線索共同工作的情況,它使得程式設計人員可以很方便地開發出具有多執行緒功能,能同時處理多個任務的功能強大的應用程式。雖然執行執行緒給人一種幾個事件同時發生的感覺,但這只是一種錯覺,因為計算機在任何給定的時刻只能執行那些執行緒中的一個。為了建立這些執行緒正在同步執行的感覺,Java快速地把控制從一個執行緒切換到另一個執行緒。
觀察下列程式碼:

  1. <spanstyle="font-size:12px;">  public static void main(String[] args) {  
  2.         // TODO Auto-generated method stub  
  3.         while(true) {  
  4.             System.out.println("JAVA");  
  5.         }  
  6.         while(true) {  
  7.             System.out.println("C++");  
  8.         }  
  9.     }</
    span>

        上述程式碼是有問題的,因為第二個while語句是永遠沒有機會執行的程式碼。如果能在程式中建立兩個執行緒,每個執行緒分別執行一個while迴圈,那麼兩個迴圈就都有機會執行,即一個執行緒中的while語句執行一段時間後,就會輪到另一個執行緒中的while語句執行一段時間,這是因為Java虛擬機器(JVM)負責管理這些執行緒,這CPU將被輪流執行,使得每個執行緒有機會使用CPU資源.

         1.執行緒與程序

         程序是程式的一次動態執行過程,它對應了從程式碼載入、執行至執行完畢的一個完整過程,這個過程也是程序本身從產生、發展至消亡的過程。執行緒是比程序更小的執行單位。一個程序在其執行過程中,可以產生多個執行緒,形成多條執行線索,每條線索,即每個執行緒也有它自身的產生、存在和消亡的過程,也是一個動態的概念。每個程序都有一段專用的記憶體區域,與此不同的是,執行緒間可以共享相同的記憶體單元(包括程式碼與資料),並利用這些共享單元來實現資料交換、實時通訊與必要的同步操作。多執行緒的程式能更好地表達和解決現實世界的具體問題,是計算機應用開發和程式設計的一個必然發展趨勢。
         每個Java程式都有一個預設的主執行緒。Java應用程式總是從主類的main方法開始執行。當JVM載入程式碼,發現main方法之後,就會啟動一個執行緒,這個執行緒稱作“主執行緒”,該執行緒負責執行main方法。在main方法的執行中再建立的執行緒,就稱為程式中的其他執行緒。如果main方法中沒有建立其他的執行緒,那麼當main方法執行完最後一個語句,即main方法返回時,JVM就會結束Java應用程式。如果main方法中又建立了其他執行緒,那麼JVM就要在主執行緒和其他執行緒之間輪流切換,保證每個執行緒都有機會使用CPU資源,main方法即使執行完最後的語句,JVM也不會結束程式,JVM一直要等到程式中的所有執行緒都結束之後,才結束Java應用程式。

 2.執行緒的狀態與生命週期
         Java使用Thread類及其子類的物件來表示執行緒,新建的執行緒在它的一個完整的生命週期中通常要經歷如下的4種狀態。
         (1)新建
 當一個Thread類或其子類的物件被宣告並建立時,新生的執行緒物件處於新建狀態。此時它已經有了相應的記憶體空間和其他資源。
         (2)執行
         執行緒建立之後就具備了執行的條件,一旦輪到它來享用CPU資源時,即JVM將CPU的使用權切換給該執行緒時,此執行緒就可以脫離建立它的主執行緒,獨立開始自己的生命週期了。
         執行緒建立後僅僅是佔有了記憶體資源,在JVM管理的執行緒中還沒有這個執行緒,此執行緒必須呼叫startO方法(從父類繼承的方法)通知JVM,這樣JVM就會知道又有一個新執行緒捧隊等候切換了。
         當JVM將CPU的使用權切換給執行緒時,如果執行緒是Thread的子類建立的,該類中run方法就立刻執行。所以必須在子類中重寫父類的run方法,Thread類中的run方法沒有具體內容,程式要在Thread類的子類中重寫run方法來覆蓋父類的run方法,run方法規定了該執行緒的具體使命。線上程沒有結束run0方法之前,不要讓執行緒再呼叫start0方法,否則將發生ILLegalThreadStateException異常。
         (3)中斷
        有4種原因的中斷:
         1)JVM將CPU資源從當前執行緒切換給其他執行緒,使本執行緒讓出CPU的使用權處於中斷狀態。
         2)執行緒使用CPU資源期間,執行了sleep(int millsecond)方法,使當前執行緒進入休眠狀態。slecp(int millsecond)方法是Thread類中的一個類方法,執行緒一旦執行了slecp(int millsecond)方法,就立刻讓出CPU的使用權,使當前執行緒處於中斷狀態。經過引數millsecond指定的毫秒數之後,該執行緒就重新進到執行緒佇列中捧隊等待CPU資源,以便從中斷處繼續執行。
         3)執行緒使用CPU資源期間,執行了wait0方法,使得當前執行緒進入等待狀態。等待狀態的執行緒不會主動進到執行緒佇列中排隊等待CPU資源,必須由其他執行緒呼叫notify0方法通知它,使得它重新進入到執行緒佇列中排隊等待CPU資源,以便從中斷處繼續執行。有關wait()、noftify()和notifyall()方法將在本部落格後面詳細討論。
        4)執行緒使用CPU資源期間,執行某個操作進入阻塞狀態,比如執行讀/寫操作引起阻塞。進入阻塞狀態時執行緒不能進入排隊佇列,只有當引起阻塞的原因消除後,執行緒才重新進入到執行緒佇列中排隊等待CPU資源,以便從原來中斷處繼續執行。
        (4)死亡
        處於死亡狀態的執行緒不具有繼續執行的能力。執行緒死亡的原因有二個:一個是正常執行的執行緒完成了它的全部工作,即執行完run方法中的全部語句,結束了run方法:Thread原因是執行緒被提前強制性地終止,即強制run方法結束。所謂死亡狀態就是執行緒釋放了實體,即釋放分配給執行緒物件的記憶體。現在,看一個完整的例子,通過分析執行結果闡述執行緒的4種狀態。該例子中用Thread的子類建立了兩個執行緒,模擬貓狗執行緒。 

  1. <spanstyle="font-size:12px;">public class ThreadDemo2 {  
  2.     /**一個多執行緒例子的展示  
  3.      * @黑馬ZWF  
  4.      */  
  5.     public static void main(String[] args) {  
  6.         // TODO Auto-generated method stub  
  7.         Cat c = new Cat();      //為貓類建立物件  
  8.         Dog d = new Dog();      //為狗類建立物件  
  9.         c.start();              //啟動多執行緒  
  10.         d.start();              //啟動多執行緒  
  11.         for(int x = 0; x <8; x++) {  
  12.             System.out.println("我是主人");  
  13.             }  
  14.     }  
  15. }  
  16. class Cat extends Thread {  
  17.     public void run() {             //重寫run方法  
  18.         for(int x = 0; x <8; x++) {  
  19.         System.out.println("我是貓");  
  20.         }  
  21.     }  
  22. }  
  23. class Dog extends Thread {  
  24.     public void run() {             //重寫run方法  
  25.         for(int x = 0; x <8; x++) {  
  26.             System.out.println("我是狗");  
  27.         }  
  28.     }  
  29. }</span>
執行結果如下:

二. 執行緒建立的兩種方式:繼承Thread類和使用Runnable介面

         1.利用Thread類的子類建立執行緒
          其實上面的ThreadDemo2就是繼承Thread類來進行執行緒的建立。下面我們來具體介紹如何用Thread類的子類來建立物件。
          在編寫Thread類的子類時,需要重寫父類的run()方法,其目的是規定執行緒的具體操作,否則執行緒就什麼也不做,因為父類的run()方法中沒有任何操作語句。
         下面例子中除主執行緒外還有兩個執行緒,這兩個執行緒共享一個物件,兩個執行緒在執行期間修改這個物件的成員變數。為了使結果儘量不依賴於當前CPU資源的使用情況。應當讓執行緒主動呼叫sleep方法讓出CPU的使用權進入中斷狀態,sleep方法是Thread類的靜查布法,執行緒在佔用CPU資源期間,通過呼叫sleep方法來使自己最棄CPU資源,休眠一段時間。程式碼示例如下:

  1. public class ThreadDemo3 {  
  2.     /**用Thread類的子類建立程序  
  3.      * @黑馬ZWF  
  4.      */  
  5.     public static void main(String[] args) {  
  6.         // TODO Auto-generated method stub  
  7.         ComputerSum sum = new ComputerSum();   
  8.         People teacher = new People("老師", 200, sum);     
  9.         People student = new People("學生", 200, sum);          
  10.         teacher.start() ;  
  11.         student.start() ;  
  12.     }  
  13. }  
  14. class ComputerSum {  
  15.     int sum;  
  16.     public void setSum(int n) {  
  17.         sum = n;  
  18.     }  
  19.     public int getSum() {  
  20.         return sum;  
  21.     }  
  22. }  
  23. class People extends Thread {  
  24.     int timeLength;      //執行緒休眠的時間長度  
  25.     ComputerSum sum;  
  26.     People(String name, int timeLength, ComputerSum sum) {  
  27.         setName(name);      //呼叫Thread類的方法setName為執行緒起個名字  
  28.         this.timeLength = timeLength;  
  29.         this.sum = sum;  
  30.     }  
  31.     public void run() {  
  32.         for(int i = 1; i <= 5; i++) {  
  33.             int m = sum.getSum();  
  34.             sum.setSum(m + 1);  
  35.             System.out.println("我是" + getName() +",現在的和:" + sum.getSum());  
  36.             try {  
  37.                 sleep(timeLength);  
  38.             }  
  39.             catch(InterruptedException e){  
  40.                 System.out.println("發生InterruptedException異常");  
  41.             }  
  42.         }  
  43.     }  
  44. }  

執行結果如下:

        2.使用Runnable介面建立程序(推薦)
        使用Thread子類建立執行緒的優點是:可以在子類中增加新的成員變數,使執行緒具有某種屬性,也可以在子類中新增加方法,使執行緒具有某種功能。但是,Java不支援多繼承,Thread類的子類不能再擴充套件其他的類。但是使用Runnable介面的話,就可以實現擴充套件,提高程式碼的靈活性。 
        1)Runnable介面與目標物件
         建立執行緒的另一個途徑就是用Thread類直接建立執行緒物件。使用Thread建立執行緒物件時,通常使用的構造方法是:
         thread(Runnable target)
        該構造方法中的引數是一個Runnable型別的介面,因此,在建立執行緒物件時必須向構造方法的引數傳遞一個實現Runnable介面類的例項,該例項物件稱作所創執行緒的目標物件,當執行緒呼叫start()方法後,一旦輪到它來享用CPU資源,目標物件就會自動呼叫介面中的run()方法(介面回撥),這一過程是自動實現的,使用者程式只需要讓執行緒呼叫start()方法即可,也就是說,當執行緒被排程並轉入執行狀態時,所執行的就是run()方法中所規定的操作。
         執行緒間可以共享相同的記憶體單元(包括程式碼與資料),並利用這些共享單元來實現資料交換、實時通訊與必要的同步操作。對於Thread(Runnable target)杓造方法建立的執行緒,輪到它來享用CPU資源時,目標物件就會自動呼叫介面中的run()方法,因此,對於使用同一目標物件的執行緒,目標物件的成員變數自然就是這些執行緒共亨的資料單元。另外,建立目標物件類在必要時還可以是某個特定類的子類,因此,使用Runnable介面比使用Thread類的子類更具有靈活性.下面程式碼示例是Runnable介面建立多執行緒的展示,改動自ThreadDemo2.

  1. public class ThreadDemo4 {  
  2.     /**Runnable介面建立多執行緒的展示,改動自ThreadDemo2  
  3.      * @黑馬ZWF  
  4.      */  
  5.     public static void main(String[] args) {  
  6.         // TODO Auto-generated method stub  
  7.         Cat c = new Cat();  
  8.         Dog d = new Dog();  
  9.         Thread t1 = new Thread(c);    //使用Runnable介面的建立方法  
  10.         Thread t2 = new Thread(d);  
  11.         t1.start();             //啟動多執行緒t1  
  12.         t2.start();             //啟動多執行緒t2  
  13.     }  
  14. }  
  15. class Cat implements Runnable {  
  16.     public void run() {             //重寫run方法  
  17.         for(int x = 0; x <8; x++) {  
  18. 相關推薦

    9--黑馬程式設計師--技術總結執行

    、期待與您交流! ---------------------- 一.多執行緒的概念 以往開發的程式大多是單執行緒的,即一個程式只有一條從頭至尾的執行線索。然而現實世界中的很多過程都具有多條線索同時動作的特性:例如,我們可以一邊看電視,一邊活動胳膊,如果

    黑馬程式設計師----Java基礎執行

    ------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a&g

    黑馬程式設計師--Java基礎執行

    ------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">j

    黑馬程式設計師——java基礎執行

    ---------------------- ASP.Net+Android+IOS開發、.Net培訓、期待與您交流! ---------------------- 1. Java 多執行緒程式設計     Java 語言的優勢之一就是執行緒處理較為簡單。     一般

    8--黑馬程式設計師---技術總結抽象類、內部類

    、期待與您交流! ---------------------- 一.抽象類       1.抽象類的概念       在面向物件的概念中,所有的物件都是通過類來描繪的,但是反過來,並不是所有的類都是用來描繪物件的,如果一個類中沒有 包含足夠的資訊來描繪一個具體的物

    7--黑馬程式設計師--技術總結幾個重要的關鍵字

    、期待與您交流! ---------------------- 一.static關鍵字           static表示“全域性”或者“靜態”的意思,用來修飾成員變數和成員方法,也可以形成靜態static程式碼塊,但是Java語言中沒有全域性變數的概念。   

    5--黑馬程式設計師--技術總結面向物件

    、期待與您交流! ---------------------- 一.什麼是面向物件? 1.面向物件的定義         面向物件是一種對現實世界理解和抽象的方法,是計算機程式設計技術發展到一定階段後的產物。早期的計算機程式設計是基於面向過程

    4--黑馬程式設計師--技術總結陣列

    <span style="white-space: pre; color: rgb(68, 68, 68); font-family: 'Microsoft Yahei', 微軟雅黑, Tahoma, Arial, Helvetica, STHeiti; font-

    黑馬程式設計師——方法總結網編

    ------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! ------- /* 1.IP地址類 InetAddress 所在包:java.net.InetAddress

    15個頂級Java執行面試題及回答 / Java程式設計師面試中的執行問題

    http://wenku.baidu.com/link?url=-7RVShQCzkHaRbyPdGP-oeVXgZ7t4mS2oqXevpzweesI_Heof5zqc_Wsvhhi8pZSU7xQWEp6e_XO7ch5nWaU_-x9Ja0CN_5V3K6QNl

    黑馬程式設計師』---java--深入加強--執行併發庫

    ----------- android培訓、java培訓、java學習型技術部落格、期待與您交流! ------------ 孝祥老師Java5執行緒併發庫講解---截圖示記筆記 java.util.concurrent.atomic  類 AtomicInteger

    黑馬程式設計師_基礎加強_Java執行通訊和執行併發庫

     ------- android培訓、java培訓、期待與您交流! ---------- java5的執行緒鎖技術 Lock&Condition實現執行緒同步通訊 Lock比傳統的synchronized方式更加面向物件,兩個執行緒執行的程式碼塊要實現同步互斥,

    黑馬程式設計師----Java基礎面向物件(封裝 繼承 型)(二)

    ------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a&g

    黑馬程式設計師----Java基礎面向物件(封裝 繼承 型)

    ------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a&g

    黑馬程式設計師技術部落格哲學家吃飯問題

    ----------- android培訓、java培訓、java學習型技術部落格、期待與您交流! ------------ 哲學家就餐:有五個哲學家繞著圓桌坐,每個哲學家面前有一碗麵,兩人之間有一支筷子,這樣每個哲學家左右各有一支筷子。哲學家有2個狀態,思考或者拿起筷子吃

    黑馬程式設計師——java基礎拾遺執行(二) 執行同步、執行通訊

    執行緒安全的概念:當多個執行緒同時執行一段程式碼時,如果結果和單執行緒執行時一致,而且其他變數也和預期的一致,說明是這段程式碼是執行緒安全的。但是,多執行緒執行的過程中會出現單執行緒時候不會出現的問題,大多出現在多個執行緒同時操作全域性變數或者靜態變數的時候。當出現這種

    黑馬程式設計師——Java高新技術反射學習總結

                                                                                        反射學習總結 基礎補充: Java程式中的各個Java類屬於同一類事務,描述這類事務的Java類名就是C

    黑馬程式設計師 java程式設計面向物件學習筆記總結

    ---------------------- ASP.Net+Unity開發、.Net培訓、期待與您交流! ---------------------- 繼承: 在java中,在我們要對一個事物進行封裝時,發現有某一個類的特性和要封裝的這個 類的特性相同,而我們可以在這個

    黑馬程式設計師執行

    ---------------------- Windows Phone 7手機開發、.Net培訓、期待與您交流! ---------------------- Thread類幾個重要的方法: Start():啟動執行緒; Sleep(int):靜態方法,暫停當前執行緒指定

    黑馬程式設計師----Java基礎反射

    ------- <a href="http://www.itheima.com" target="blank">android培訓</a>、<a href="http://www.itheima.com" target="blank">java培訓</a&g