<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    蘋果的成長日記

    我還是個青蘋果呀!

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      57 隨筆 :: 0 文章 :: 74 評論 :: 0 Trackbacks
    JAVA教程:解析Java的多線程機(jī)制
    http://dev.21tx.com 2005年05月03日 賽迪網(wǎng)

    一、進(jìn)程與應(yīng)用程序的區(qū)別
      
      進(jìn)程(Process)是最初定義在Unix等多用戶、多任務(wù)操作系統(tǒng)環(huán)境下用于表示應(yīng)用程序在內(nèi)存環(huán)境中基本執(zhí)行單元的概念。以Unix操作系統(tǒng)為例,進(jìn)程是Unix操作系統(tǒng)環(huán)境中的基本成分、是系統(tǒng)資源分配的基本單位。Unix操作系統(tǒng)中完成的幾乎所有用戶管理和資源分配等工作都是通過操作系統(tǒng)對應(yīng)用程序進(jìn)程的控制來實(shí)現(xiàn)的。
      
      C、C++、Java等語言編寫的源程序經(jīng)相應(yīng)的編譯器編譯成可執(zhí)行文件后,提交給計(jì)算機(jī)處理器運(yùn)行。這時,處在可執(zhí)行狀態(tài)中的應(yīng)用程序稱為進(jìn)程。從用戶角度來看,進(jìn)程是應(yīng)用程序的一個執(zhí)行過程。從操作系統(tǒng)核心角度來看,進(jìn)程代表的是操作系統(tǒng)分配的內(nèi)存、CPU時間片等資源的基本單位,是為正在運(yùn)行的程序提供的運(yùn)行環(huán)境。進(jìn)程與應(yīng)用程序的區(qū)別在于應(yīng)用程序作為一個靜態(tài)文件存儲在計(jì)算機(jī)系統(tǒng)的硬盤等存儲空間中,而進(jìn)程則是處于動態(tài)條件下由操作系統(tǒng)維護(hù)的系統(tǒng)資源管理實(shí)體。多任務(wù)環(huán)境下應(yīng)用程序進(jìn)程的主要特點(diǎn)包括:
      
      ●進(jìn)程在執(zhí)行過程中有內(nèi)存單元的初始入口點(diǎn),并且進(jìn)程存活過程中始終擁有獨(dú)立的內(nèi)存地址空間;
      
      ●進(jìn)程的生存期狀態(tài)包括創(chuàng)建、就緒、運(yùn)行、阻塞和死亡等類型;
      
      ●從應(yīng)用程序進(jìn)程在執(zhí)行過程中向CPU發(fā)出的運(yùn)行指令形式不同,可以將進(jìn)程的狀態(tài)分為用戶態(tài)和核心態(tài)。處于用戶態(tài)下的進(jìn)程執(zhí)行的是應(yīng)用程序指令、處于核心態(tài)下的應(yīng)用程序進(jìn)程執(zhí)行的是操作系統(tǒng)指令。
      
      在Unix操作系統(tǒng)啟動過程中,系統(tǒng)自動創(chuàng)建swapper、init等系統(tǒng)進(jìn)程,用于管理內(nèi)存資源以及對用戶進(jìn)程進(jìn)行調(diào)度等。在Unix環(huán)境下無論是由操作系統(tǒng)創(chuàng)建的進(jìn)程還要由應(yīng)用程序執(zhí)行創(chuàng)建的進(jìn)程,均擁有唯一的進(jìn)程標(biāo)識(PID)。

    二、進(jìn)程與Java線程的區(qū)別
      
      
      應(yīng)用程序在執(zhí)行過程中存在一個內(nèi)存空間的初始入口點(diǎn)地址、一個程序執(zhí)行過程中的代碼執(zhí)行序列以及用于標(biāo)識進(jìn)程結(jié)束的內(nèi)存出口點(diǎn)地址,在進(jìn)程執(zhí)行過程中的每一時間點(diǎn)均有唯一的處理器指令與內(nèi)存單元地址相對應(yīng)。
      
      Java語言中定義的線程(Thread)同樣包括一個內(nèi)存入口點(diǎn)地址、一個出口點(diǎn)地址以及能夠順序執(zhí)行的代碼序列。但是進(jìn)程與線程的重要區(qū)別在于線程不能夠單獨(dú)執(zhí)行,它必須運(yùn)行在處于活動狀態(tài)的應(yīng)用程序進(jìn)程中,因此可以定義線程是程序內(nèi)部的具有并發(fā)性的順序代碼流。
      
      Unix操作系統(tǒng)和Microsoft Windows操作系統(tǒng)支持多用戶、多進(jìn)程的并發(fā)執(zhí)行,而Java語言支持應(yīng)用程序進(jìn)程內(nèi)部的多個執(zhí)行線程的并發(fā)執(zhí)行。多線程的意義在于一個應(yīng)用程序的多個邏輯單元可以并發(fā)地執(zhí)行。但是多線程并不意味著多個用戶進(jìn)程在執(zhí)行,操作系統(tǒng)也不把每個線程作為獨(dú)立的進(jìn)程來分配獨(dú)立的系統(tǒng)資源。進(jìn)程可以創(chuàng)建其子進(jìn)程,子進(jìn)程與父進(jìn)程擁有不同的可執(zhí)行代碼和數(shù)據(jù)內(nèi)存空間。而在用于代表應(yīng)用程序的進(jìn)程中多個線程共享數(shù)據(jù)內(nèi)存空間,但保持每個線程擁有獨(dú)立的執(zhí)行堆棧和程序執(zhí)行上下文(Context)。
      
      基于上述區(qū)別,線程也可以稱為輕型進(jìn)程 (Light Weight Process,LWP)。不同線程間允許任務(wù)協(xié)作和數(shù)據(jù)交換,使得在計(jì)算機(jī)系統(tǒng)資源消耗等方面非常廉價。
      
      線程需要操作系統(tǒng)的支持,不是所有類型的計(jì)算機(jī)都支持多線程應(yīng)用程序。Java程序設(shè)計(jì)語言將線程支持與語言運(yùn)行環(huán)境結(jié)合在一起,提供了多任務(wù)并發(fā)執(zhí)行的能力。這就好比一個人在處理家務(wù)的過程中,將衣服放到洗衣機(jī)中自動洗滌后將大米放在電飯鍋里,然后開始做菜。等菜做好了,飯熟了同時衣服也洗好了。
      
      需要注意的是:在應(yīng)用程序中使用多線程不會增加 CPU 的數(shù)據(jù)處理能力。只有在多CPU 的計(jì)算機(jī)或者在網(wǎng)絡(luò)計(jì)算體系結(jié)構(gòu)下,將Java程序劃分為多個并發(fā)執(zhí)行線程后,同時啟動多個線程運(yùn)行,使不同的線程運(yùn)行在基于不同處理器的Java虛擬機(jī)中,才能提高應(yīng)用程序的執(zhí)行效率。

    另外,如果應(yīng)用程序必須等待網(wǎng)絡(luò)連接或數(shù)據(jù)庫連接等數(shù)據(jù)吞吐速度相對較慢的資源時,多線程應(yīng)用程序是非常有利的。基于Internet的應(yīng)用程序有必要是多線程類型的,例如,當(dāng)開發(fā)要支持大量客戶機(jī)的服務(wù)器端應(yīng)用程序時,可以將應(yīng)用程序創(chuàng)建成多線程形式來響應(yīng)客戶端的連接請求,使每個連接用戶獨(dú)占一個客戶端連接線程。這樣,用戶感覺服務(wù)器只為連接用戶自己服務(wù),從而縮短了服務(wù)器的客戶端響應(yīng)時間。
      
      
    三、Java語言的多線程程序設(shè)計(jì)方法
      
      
      利用Java語言實(shí)現(xiàn)多線程應(yīng)用程序的方法很簡單。根據(jù)多線程應(yīng)用程序繼承或?qū)崿F(xiàn)對象的不同可以采用兩種方式:一種是應(yīng)用程序的并發(fā)運(yùn)行對象直接繼承Java的線程類Thread;另外一種方式是定義并發(fā)執(zhí)行對象實(shí)現(xiàn)Runnable接口。
      
      繼承Thread類的多線程程序設(shè)計(jì)方法
      
      Thread 類是JDK中定義的用于控制線程對象的類,在該類中封裝了用于進(jìn)行線程控制的方法。見下面的示例代碼:
      
      [code]//Consumer.java
      import java.util.*;
      class Consumer extends Thread
      {
       int nTime;
       String strConsumer;
       public Consumer(int nTime, String strConsumer)
       {
       this.nTime = nTime;
       this.strConsumer = strConsumer;
       }
       public void run()
       {
      while(true)
      {
       try
      {
       System.out.println("Consumer name:"+strConsumer+"\n");
       Thread.sleep(nTime);
       }
      catch(Exception e)
      {
       e.printStackTrace();
       }
      }
       }
      static public void main(String args[])
      {
       Consumer aConsumer = new Consumer (1000, "aConsumer");
       aConsumer.start();
       Consumer bConsumer = new Consumer (2000, "bConsumer");
       bConsumer.start();
       Consumer cConsumer = new Consumer (3000, "cConsumer ");
       cConsumer.start();
      }
      } [/code]
      
      
      
      
      從上面的程序代碼可以看出:多線程執(zhí)行地下Consumer繼承Java語言中的線程類Thread并且在main方法中創(chuàng)建了三個Consumer對象的實(shí)例。當(dāng)調(diào)用對象實(shí)例的start方法時,自動調(diào)用Consumer類中定義的run方法啟動對象線程運(yùn)行。線程運(yùn)行的結(jié)果是每間隔nTime時間打印出對象實(shí)例中的字符串成員變量strConsumer的內(nèi)容。
      
      可以總結(jié)出繼承Thread類的多線程程序設(shè)計(jì)方法是使應(yīng)用程序類繼承Thread類并且在該類的run方法中實(shí)現(xiàn)并發(fā)性處理過程。
      
      實(shí)現(xiàn)Runnable接口的多線程程序設(shè)計(jì)方法
      
      Java語言中提供的另外一種實(shí)現(xiàn)多線程應(yīng)用程序的方法是多線程對象實(shí)現(xiàn)Runnable接口并且在該類中定義用于啟動線程的run方法。這種定義方式的好處在于多線程應(yīng)用對象可以繼承其它對象而不是必須繼承Thread類,從而能夠增加類定義的邏輯性。
      
      實(shí)現(xiàn)Runnable接口的多線程應(yīng)用程序框架代碼如下所示:
      
      //Consumer.java
      import java.util.*;
      class Consumer implements Runnable
      {
       … …
      public Consumer(int nTime, String strConsumer){… …}
      public void run(){… …}
      static public void main(String args[])
      {
      Thread aConsumer = new Thread(new Consumer(1000, "aConsumer"));
      aConsumer.start();
      //其它對象實(shí)例的運(yùn)行線程
       //… …
       }
      }
      
      從上述代碼可以看出:該類實(shí)現(xiàn)了Runnable接口并且在該類中定義了run方法。這種多線程應(yīng)用程序的實(shí)現(xiàn)方式與繼承Thread類的多線程應(yīng)用程序的重要區(qū)別在于啟動多線程對象的方法設(shè)計(jì)方法不同。在上述代碼中,通過創(chuàng)建Thread對象實(shí)例并且將應(yīng)用對象作為創(chuàng)建Thread類實(shí)例的參數(shù)。

    四、線程間的同步
      
      Java應(yīng)用程序的多個線程共享同一進(jìn)程的數(shù)據(jù)資源,多個用戶線程在并發(fā)運(yùn)行過程中可能同時訪問具有敏感性的內(nèi)容。在Java中定義了線程同步的概念,實(shí)現(xiàn)對共享資源的一致性維護(hù)。下面以筆者最近開發(fā)的移動通信計(jì)費(fèi)系統(tǒng)中線程間同步控制方法,說明Java語言中多線程同步方式的實(shí)現(xiàn)過程。
      
      在沒有多線程同步控制策略條件下的客戶賬戶類定義框架代碼如下所示:
      
      public class RegisterAccount
      {
      float fBalance;
      //客戶繳費(fèi)方法
      public void deposit(float fFees){ fBalance += fFees; }
      //通話計(jì)費(fèi)方法
      public void withdraw(float fFees){ fBalance -= fFees; }
      … …
      }

      
      
      
      
      讀者也許會認(rèn)為:上述程序代碼完全能夠滿足計(jì)費(fèi)系統(tǒng)實(shí)際的需要。確實(shí),在單線程環(huán)境下該程序確實(shí)是可靠的。但是,多進(jìn)程并發(fā)運(yùn)行的情況是怎樣的呢?假設(shè)發(fā)生這種情況:客戶在客戶服務(wù)中心進(jìn)行繳費(fèi)的同時正在利用移動通信設(shè)備進(jìn)行通話,客戶通話結(jié)束時計(jì)費(fèi)系統(tǒng)啟動計(jì)費(fèi)進(jìn)程,而同時服務(wù)中心的工作人員也提交繳費(fèi)進(jìn)程運(yùn)行。讀者可以看到如果發(fā)生這種情況,對客戶賬戶的處理是不嚴(yán)肅的。
      
      如何解決這種問題呢?很簡單,在RegisterAccount類方法定義中加上用于標(biāo)識同步方法的關(guān)鍵字synchronized。這樣,在同步方法執(zhí)行過程中該方法涉及的共享資源(在上述代碼中為fBalance成員變量)將被加上共享鎖以確保在方法運(yùn)行期間只有該方法能夠?qū)蚕碣Y源進(jìn)行訪問,直到該方法的線程運(yùn)行結(jié)束打開共享鎖,其它線程才能夠訪問這些共享資源。在共享鎖沒有打開的時候其它訪問共享資源的線程處于阻塞狀態(tài)。
      
      進(jìn)行線程同步策略控制后的RegisterAccount類定義如下面代碼所示:
      
      public class RegisterAccount
      {
      float fBalance;
      public synchronized void deposit(float fFees){ fBalance += fFees; }
      public synchronized void withdraw(float fFees){ fBalance -= fFees; }
      … …
      }

      
      從經(jīng)過線程同步機(jī)制定義后的代碼形式可以看出:在對共享資源進(jìn)行訪問的方法訪問屬性關(guān)鍵字(public)后附加同步定義關(guān)鍵字synchronized,使得同步方法在對共享資源訪問的時候,為這些敏感資源附加共享鎖來控制方法執(zhí)行期間的資源獨(dú)占性,實(shí)現(xiàn)了應(yīng)用系統(tǒng)數(shù)據(jù)資源的一致性管理和維護(hù)。


    五、 Java線程的管理
      
      
      線程的狀態(tài)控制
      
      在這里需要明確的是:無論采用繼承Thread類還是實(shí)現(xiàn)Runnable接口來實(shí)現(xiàn)應(yīng)用程序的多線程能力,都需要在該類中定義用于完成實(shí)際功能的run方法,這個run方法稱為線程體(Thread Body)。按照線程體在計(jì)算機(jī)系統(tǒng)內(nèi)存中的狀態(tài)不同,可以將線程分為創(chuàng)建、就緒、運(yùn)行、睡眠、掛起和死亡等類型。這些線程狀態(tài)類型下線程的特征為:
      
      創(chuàng)建狀態(tài):當(dāng)利用new關(guān)鍵字創(chuàng)建線程對象實(shí)例后,它僅僅作為一個對象實(shí)例存在,JVM沒有為其分配CPU時間片等線程運(yùn)行資源;
      
      就緒狀態(tài):在處于創(chuàng)建狀態(tài)的線程中調(diào)用start方法將線程的狀態(tài)轉(zhuǎn)換為就緒狀態(tài)。這時,線程已經(jīng)得到除CPU時間之外的其它系統(tǒng)資源,只等JVM的線程調(diào)度器按照線程的優(yōu)先級對該線程進(jìn)行調(diào)度,從而使該線程擁有能夠獲得CPU時間片的機(jī)會。
      
      睡眠狀態(tài):在線程運(yùn)行過程中可以調(diào)用sleep方法并在方法參數(shù)中指定線程的睡眠時間將線程狀態(tài)轉(zhuǎn)換為睡眠狀態(tài)。這時,該線程在不釋放占用資源的情況下停止運(yùn)行指定的睡眠時間。時間到達(dá)后,線程重新由JVM線程調(diào)度器進(jìn)行調(diào)度和管理。
      
      掛起狀態(tài):可以通過調(diào)用suspend方法將線程的狀態(tài)轉(zhuǎn)換為掛起狀態(tài)。這時,線程將釋放占用的所有資源,由JVM調(diào)度轉(zhuǎn)入臨時存儲空間,直至應(yīng)用程序調(diào)用resume方法恢復(fù)線程運(yùn)行。
      
      死亡狀態(tài):當(dāng)線程體運(yùn)行結(jié)束或者調(diào)用線程對象的stop方法后線程將終止運(yùn)行,由JVM收回線程占用的資源。
      
      在Java線程類中分別定義了相應(yīng)的方法,用于在應(yīng)用程序中對線程狀態(tài)進(jìn)行控制和管理。
      
      線程的調(diào)度
      
      線程調(diào)用的意義在于JVM應(yīng)對運(yùn)行的多個線程進(jìn)行系統(tǒng)級的協(xié)調(diào),以避免多個線程爭用有限資源而導(dǎo)致應(yīng)用系統(tǒng)死機(jī)或者崩潰。
      
      為了線程對于操作系統(tǒng)和用戶的重要性區(qū)分開,Java定義了線程的優(yōu)先級策略。Java將線程的優(yōu)先級分為10個等級,分別用1-10之間的數(shù)字表示。數(shù)字越大表明線程的級別越高。相應(yīng)地,在Thread類中定義了表示線程最低、最高和普通優(yōu)先級的成員變量MIN_PRIORITY、MAX_PRIORITY和NORMAL_PRIORITY,代表的優(yōu)先級等級分別為1、10和5。當(dāng)一個線程對象被創(chuàng)建時,其默認(rèn)的線程優(yōu)先級是5。
      
      為了控制線程的運(yùn)行策略,Java定義了線程調(diào)度器來監(jiān)控系統(tǒng)中處于就緒狀態(tài)的所有線程。線程調(diào)度器按照線程的優(yōu)先級決定那個線程投入處理器運(yùn)行。在多個線程處于就緒狀態(tài)的條件下,具有高優(yōu)先級的線程會在低優(yōu)先級線程之前得到執(zhí)行。線程調(diào)度器同樣采用"搶占式"策略來調(diào)度線程執(zhí)行,即當(dāng)前線程執(zhí)行過程中有較高優(yōu)先級的線程進(jìn)入就緒狀態(tài),則高優(yōu)先級的線程立即被調(diào)度執(zhí)行。具有相同優(yōu)先級的所有線程采用輪轉(zhuǎn)的方式來共同分配CPU時間片。
      
      在應(yīng)用程序中設(shè)置線程優(yōu)先級的方法很簡單,在創(chuàng)建線程對象之后可以調(diào)用線程對象的setPriority方法改變該線程的運(yùn)行優(yōu)先級,同樣可以調(diào)用getPriority方法獲取當(dāng)前線程的優(yōu)先級。
      
      在Java中比較特殊的線程是被稱為守護(hù)(Daemon)線程的低級別線程。這個線程具有最低的優(yōu)先級,用于為系統(tǒng)中的其它對象和線程提供服務(wù)。將一個用戶線程設(shè)置為守護(hù)線程的方式是在線程對象創(chuàng)建之前調(diào)用線程對象的setDaemon方法。典型的守護(hù)線程例子是JVM中的系統(tǒng)資源自動回收線程,它始終在低級別的狀態(tài)中運(yùn)行,用于實(shí)時監(jiān)控和管理系統(tǒng)中的可回收資源。
      
      線程分組管理
      
      Java定義了在多線程運(yùn)行系統(tǒng)中的線程組(ThreadGroup)對象,用于實(shí)現(xiàn)按照特定功能對線程進(jìn)行集中式分組管理。用戶創(chuàng)建的每個線程均屬于某線程組,這個線程組可以在線程創(chuàng)建時指定,也可以不指定線程組以使該線程處于默認(rèn)的線程組之中。但是,一旦線程加入某線程組,該線程就一直存在于該線程組中直至線程死亡,不能在中途改變線程所屬的線程組。
      
      當(dāng)Java的Application應(yīng)用程序運(yùn)行時,JVM創(chuàng)建名稱為main的線程組。除非單獨(dú)指定,在該應(yīng)用程序中創(chuàng)建的線程均屬于main線程組。在main線程組中可以創(chuàng)建其它名稱的線程組并將其它線程加入到該線程組中,依此類推,構(gòu)成線程和線程組之間的樹型管理和繼承關(guān)系。
      
      與線程類似,可以針對線程組對象進(jìn)行線程組的調(diào)度、狀態(tài)管理以及優(yōu)先級設(shè)置等。在對線程組進(jìn)行管理過程中,加入到某線程組中的所有線程均被看作統(tǒng)一的對象。

    六、小結(jié):
    本文針對Java平臺中線程的性質(zhì)和應(yīng)用程序的多線程策略進(jìn)行了分析和講解。
      
      與其它操作系統(tǒng)環(huán)境不同,Java運(yùn)行環(huán)境中的線程類似于多用戶、多任務(wù)操作系統(tǒng)環(huán)境下的進(jìn)程,但在進(jìn)程和線程的運(yùn)行及創(chuàng)建方式等方面,進(jìn)程與Java線程具有明顯區(qū)別。
      
      Unix操作系統(tǒng)環(huán)境下,應(yīng)用程序可以利用fork函數(shù)創(chuàng)建子進(jìn)程,但子進(jìn)程與該應(yīng)用程序進(jìn)程擁有獨(dú)立的地址空間、系統(tǒng)資源和代碼執(zhí)行單元,并且進(jìn)程的調(diào)度是由操作系統(tǒng)來完成的,使得在應(yīng)用進(jìn)程之間進(jìn)行通信和線程協(xié)調(diào)相對復(fù)雜。而Java應(yīng)用程序中的多線程則是共享同一應(yīng)用系統(tǒng)資源的多個并行代碼執(zhí)行體,線程之間的通信和協(xié)調(diào)方法相對簡單
      
      可以說:Java語言對應(yīng)用程序多線程能力的支持增強(qiáng)了Java作為網(wǎng)絡(luò)程序設(shè)計(jì)語言的優(yōu)勢,為實(shí)現(xiàn)分布式應(yīng)用系統(tǒng)中多客戶端的并發(fā)訪問以及提高服務(wù)器的響應(yīng)效率奠定堅(jiān)實(shí)基礎(chǔ)。
    posted on 2005-06-24 09:43 蘋果 閱讀(502) 評論(1)  編輯  收藏 所屬分類: J2EE/JAVA學(xué)習(xí)

    評論

    # re: 【轉(zhuǎn)載至賽迪網(wǎng)】解析java的多線程機(jī)制 2005-06-24 09:50 蘋果
    一般來說,我們把正在計(jì)算機(jī)中執(zhí)行的程序叫做"進(jìn)程"(Process) ,而不將其
    稱為程序(Program)。所謂"線程"(Thread),是"進(jìn)程"中某個單一順序的控制流。
    新興的操作系統(tǒng),如Mac,Windows NT,Windows 95等,大多采用多線程的概念,把線
    程視為基本執(zhí)行單位。線程也是Java中的相當(dāng)重要的組成部分之一。

      甚至最簡單的Applet也是由多個線程來完成的。在Java中,任何一個Applet的
    paint()和update()方法都是由AWT(Abstract Window Toolkit)繪圖與事件處理線
    程調(diào)用的,而Applet 主要的里程碑方法——init(),start(),stop()和destory()
    ——是由執(zhí)行該Applet的應(yīng)用調(diào)用的。

      單線程的概念沒有什么新的地方,真正有趣的是在一個程序中同時使用多個線
    程來完成不同的任務(wù)。某些地方用輕量進(jìn)程(Lightweig ht Process)來代替線程
    ,線程與真正進(jìn)程的相似性在于它們都是單一順序控制流。然而線程被認(rèn)為輕量是
    由于它運(yùn)行于整個程序的上下文內(nèi),能使用整個程序共有的資源和程序環(huán)境。

      作為單一順序控制流,在運(yùn)行的程序內(nèi)線程必須擁有一些資源作為必要的開銷
    。例如,必須有執(zhí)行堆棧和程序計(jì)數(shù)器。在線程內(nèi)執(zhí)行的代碼只在它的上下文中起
    作用,因此某些地方用"執(zhí)行上下文"來代替"線程"。

      2.線程屬性

      為了正確有效地使用線程,必須理解線程的各個方面并了解Java 實(shí)時系統(tǒng)。
    必須知道如何提供線程體、線程的生命周期、實(shí)時系統(tǒng)如 何調(diào)度線程、線程組、
    什么是幽靈線程(Demo nThread)。

      (1)線程體
      所有的操作都發(fā)生在線程體中,在Java中線程體是從Thread類繼承的run()方
    法,或?qū)崿F(xiàn)Runnable接口的類中的run()方法。當(dāng)線程產(chǎn)生并初始化后,實(shí)時系統(tǒng)調(diào)
    用它的run()方法。run()方法內(nèi)的代碼實(shí)現(xiàn)所產(chǎn)生線程的行為,它是線程的主要部
    分。

      (2)線程狀態(tài)
      附圖表示了線程在它的生命周期內(nèi)的任何時刻所能處的狀態(tài)以及引起狀態(tài)改
    變的方法。這圖并不是完整的有限狀態(tài)圖,但基本概括了線程中比較感興趣和普遍
    的方面。以下討論有關(guān)線程生命周期以此為據(jù)。


      ●新線程態(tài)(New Thread)
      產(chǎn)生一個Thread對象就生成一個新線程。當(dāng)線程處于"新線程"狀態(tài)時,僅僅是
    一個空線程對象,它還沒有分配到系統(tǒng)資源。因此只能啟動或終止它。任何其他操
    作都會引發(fā)異常。
      ●可運(yùn)行態(tài)(Runnable)
      start()方法產(chǎn)生運(yùn)行線程所必須的資源,調(diào)度線程執(zhí)行,并且調(diào)用線程的run
    ()方法。在這時線程處于可運(yùn)行態(tài)。該狀態(tài)不稱為運(yùn)行態(tài)是因?yàn)檫@時的線程并不
    總是一直占用處理機(jī)。特別是對于只有一個處理機(jī)的PC而言,任何時刻只能有一個
    處于可運(yùn)行態(tài)的線程占用處理 機(jī)。Java通過調(diào)度來實(shí)現(xiàn)多線程對處理機(jī)的共享。

      ●非運(yùn)行態(tài)(Not Runnable)
      當(dāng)以下事件發(fā)生時,線程進(jìn)入非運(yùn)行態(tài)。
      ①suspend()方法被調(diào)用;
      ②sleep()方法被調(diào)用;
      ③線程使用wait()來等待條件變量;
      ④線程處于I/O等待。
      ●死亡態(tài)(Dead)
      當(dāng)run()方法返回,或別的線程調(diào)用stop()方法,線程進(jìn)入死亡態(tài) 。通常Appl
    et使用它的stop()方法來終止它產(chǎn)生的所有線程。

      (3)線程優(yōu)先級
      雖然我們說線程是并發(fā)運(yùn)行的。然而事實(shí)常常并非如此。正如前面談到的,當(dāng)
    系統(tǒng)中只有一個CPU時,以某種順序在單CPU情況下執(zhí)行多線程被稱為調(diào)度(schedu
    ling)。Java采用的是一種簡單、固定的調(diào)度法,即固定優(yōu)先級調(diào)度。這種算法是
    根據(jù)處于可運(yùn)行態(tài)線程的相對優(yōu)先級來實(shí)行調(diào)度。當(dāng)線程產(chǎn)生時,它繼承原線程的
    優(yōu)先級。在需要時可對優(yōu)先級進(jìn)行修改。在任何時刻,如果有多條線程等待運(yùn)行,
    系統(tǒng)選擇優(yōu)先級最高的可運(yùn)行線程運(yùn)行。只有當(dāng)它停止、自動放棄、或由于某種
    原因成為非運(yùn)行態(tài)低優(yōu)先級的線程才能運(yùn)行。如果兩個線程具有相同的優(yōu)先級,它
    們將被交替地運(yùn)行。
      Java實(shí)時系統(tǒng)的線程調(diào)度算法還是強(qiáng)制性的,在任何時刻,如果一個比其他線
    程優(yōu)先級都高的線程的狀態(tài)變?yōu)榭蛇\(yùn)行態(tài),實(shí)時系統(tǒng)將選擇該線程來運(yùn)行。

      (4)幽靈線程
      任何一個Java線程都能成為幽靈線程。它是作為運(yùn)行于同一個進(jìn)程內(nèi)的對象
    和線程的服務(wù)提供者。例如,HotJava瀏覽器有一個稱為" 后臺圖片閱讀器"的幽靈
    線程,它為需要圖片的對象和線程從文件系統(tǒng)或網(wǎng)絡(luò)讀入圖片。
      幽靈線程是應(yīng)用中典型的獨(dú)立線程。它為同一應(yīng)用中的其他對象和線程提供
    服務(wù)。幽靈線程的run()方法一般都是無限循環(huán),等待服務(wù)請求。

      (5)線程組
      每個Java線程都是某個線程組的成員。線程組提供一種機(jī)制,使得多個線程集
    于一個對象內(nèi),能對它們實(shí)行整體操作。譬如,你能用一個方法調(diào)用來啟動或掛起
    組內(nèi)的所有線程。Java線程組由ThreadGroup類實(shí)現(xiàn)。
      當(dāng)線程產(chǎn)生時,可以指定線程組或由實(shí)時系統(tǒng)將其放入某個缺省的線程組內(nèi)。
    線程只能屬于一個線程組,并且當(dāng)線程產(chǎn)生后不能改變它所屬的線程組。

      3.多線程程序

      對于多線程的好處這就不多說了。但是,它同樣也帶來了某些新的麻煩。只要
    在設(shè)計(jì)程序時特別小心留意,克服這些麻煩并不算太困難。

      (1)同步線程
      許多線程在執(zhí)行中必須考慮與其他線程之間共享數(shù)據(jù)或協(xié)調(diào)執(zhí)行狀態(tài)。這就
    需要同步機(jī)制。在Java中每個對象都有一把鎖與之對應(yīng)。但Java不提供單獨(dú)的lo
    ck和unlock操作。它由高層的結(jié)構(gòu)隱式實(shí)現(xiàn), 來保證操作的對應(yīng)。(然而,我們注
    意到Java虛擬機(jī)提供單獨(dú)的monito renter和monitorexit指令來實(shí)現(xiàn)lock和unlo
    ck操作。)
      synchronized語句計(jì)算一個對象引用,試圖對該對象完成鎖操作, 并且在完成
    鎖操作前停止處理。當(dāng)鎖操作完成synchronized語句體得到執(zhí)行。當(dāng)語句體執(zhí)行
    完畢(無論正常或異常),解鎖操作自動完成。作為面向?qū)ο蟮恼Z言,synchronized
    經(jīng)常與方法連用。一種比較好的辦法是,如果某個變量由一個線程賦值并由別的線
    程引用或賦值,那么所有對該變量的訪問都必須在某個synchromized語句或synch
    ronized方法內(nèi)。
      現(xiàn)在假設(shè)一種情況:線程1與線程2都要訪問某個數(shù)據(jù)區(qū),并且要求線程1的訪
    問先于線程2, 則這時僅用synchronized是不能解決問題的。這在Unix或Windows
    NT中可用Simaphore來實(shí)現(xiàn)。而Java并不提供。在Java中提供的是wait()和noti
    fy()機(jī)制。使用如下:
      synchronized method-1(…){ call by thread 1.
      ∥access data area;
      available=true;
      notify()
      }
      synchronized method-2(…){∥call by thread 2.
      while(!available)
      try{
      wait();∥wait for notify().
      }catch (Interrupted Exception e){
      }
      ∥access data area
      }
      其中available是類成員變量,置初值為false。
      如果在method-2中檢查available為假,則調(diào)用wait()。wait()的作用是使線
    程2進(jìn)入非運(yùn)行態(tài),并且解鎖。在這種情況下,method-1可以被線程1調(diào)用。當(dāng)執(zhí)行
    notify()后。線程2由非運(yùn)行態(tài)轉(zhuǎn)變?yōu)榭蛇\(yùn)行態(tài)。當(dāng)method-1調(diào)用返回后。線程2
    可重新對該對象加鎖,加鎖成功后執(zhí)行wait()返回后的指令。這種機(jī)制也能適用于
    其他更復(fù)雜的情況。

      (2)死鎖
      如果程序中有幾個競爭資源的并發(fā)線程,那么保證均衡是很重要的。系統(tǒng)均衡
    是指每個線程在執(zhí)行過程中都能充分訪問有限的資源。系統(tǒng)中沒有餓死和死鎖的
    線程。Java并不提供對死鎖的檢測機(jī)制。對大多數(shù)的Java程序員來說防止死鎖是
    一種較好的選擇。最簡單的防止死鎖的方法是對競爭的資源引入序號,如果一個線
    程需要幾個資源,那么它必須先得到小序號的資源,再申請大序號的資源。

      4.小結(jié)

      線程是Java中的重要內(nèi)容,多線程是Java的一個特點(diǎn)。雖然Java的同步互斥不
    如某些系統(tǒng)那么豐富,但適當(dāng)?shù)厥褂盟鼈円材苁盏綕M意的效果。   回復(fù)  更多評論
      

    主站蜘蛛池模板: 午夜老司机免费视频| 亚洲欧洲日产国码无码网站| 日日躁狠狠躁狠狠爱免费视频| 狠狠综合久久综合88亚洲| 99re6在线精品视频免费播放 | 久久亚洲精品中文字幕| 国产va免费精品观看精品| 特级做a爰片毛片免费看| 久久久久亚洲精品天堂| 免费看国产一级特黄aa大片| 免费91麻豆精品国产自产在线观看 | 嘿嘿嘿视频免费网站在线观看| 国产精品亚洲专区无码WEB| 亚洲AV无码码潮喷在线观看| 成人午夜免费福利| 国产成人AV免费观看| 亚洲乱码中文字幕在线| 久久精品亚洲一区二区| 免费亚洲视频在线观看| 成人午夜免费福利视频| 中文字幕av免费专区| 精品久久久久亚洲| 亚洲熟妇色自偷自拍另类| 亚洲伊人久久大香线蕉综合图片| 最近最好的中文字幕2019免费 | 国产偷国产偷亚洲清高APP| 91天堂素人精品系列全集亚洲 | 色拍自拍亚洲综合图区| 亚洲精品国产va在线观看蜜芽| 日本高清不卡中文字幕免费| 亚洲午夜国产精品无卡| 热99re久久免费视精品频软件| 国产精品免费无遮挡无码永久视频 | 亚洲成AV人片久久| 久久国产亚洲精品麻豆| 亚洲?v无码国产在丝袜线观看| 国产精品69白浆在线观看免费 | 日日操夜夜操免费视频| 最近最新MV在线观看免费高清| 免费在线观看一级片| 中文永久免费观看网站|