進程與應用程序的區別

一、進程與應用程序的區別      進程(Process)是最初定義在Unix等多用戶、多任務操作系統環境下用於表示應用程序在內存環境中基本執行單元的概念。以Unix操作系統爲例,進程是Unix操作系統環境中的基本成分、是系統資源分配的基本單位。Unix操作系統中完成的幾乎所有用戶管理和資源分配等工作都是通過操作系統對應用程序進程的控制來實現的。      C、C++、Java等語言編寫的源程序經相應的編譯器編譯成可執行文件後,提交給計算機處理器運行。這時,處在可執行狀態中的應用程序稱爲進程。從用戶角度來看,進程是應用程序的一個執行過程。從操作系統核心角度來看,進程代表的是操作系統分配的內存、CPU時間片等資源的基本單位,是爲正在運行的程序提供的運行環境。進程與應用程序的區別在於應用程序作爲一個靜態文件存儲在計算機系統的硬盤等存儲空間中,而進程則是處於動態條件下由操作系統維護的系統資源管理實體。多任務環境下應用程序進程的主要特點包括:      ●進程在執行過程中有內存單元的初始入口點,並且進程存活過程中始終擁有獨立的內存地址空間;      ●進程的生存期狀態包括創建、就緒、運行、阻塞和死亡等類型;      ●從應用程序進程在執行過程中向CPU發出的運行指令形式不同,可以將進程的狀態分爲用戶態和核心態。處於用戶態下的進程執行的是應用程序指令、處於核心態下的應用程序進程執行的是操作系統指令。      在Unix操作系統啓動過程中,系統自動創建swapper、init等系統進程,用於管理內存資源以及對用戶進程進行調度等。在Unix環境下無論是由操作系統創建的進程還要由應用程序執行創建的進程,均擁有唯一的進程標識(PID)。 二、進程與Java線程的區別         應用程序在執行過程中存在一個內存空間的初始入口點地址、一個程序執行過程中的代碼執行序列以及用於標識進程結束的內存出口點地址,在進程執行過程中的每一時間點均有唯一的處理器指令與內存單元地址相對應。      Java語言中定義的線程(Thread)同樣包括一個內存入口點地址、一個出口點地址以及能夠順序執行的代碼序列。但是進程與線程的重要區別在於線程不能夠單獨執行,它必須運行在處於活動狀態的應用程序進程中,因此可以定義線程是程序內部的具有併發性的順序代碼流。      Unix操作系統和Microsoft Windows操作系統支持多用戶、多進程的併發執行,而Java語言支持應用程序進程內部的多個執行線程的併發執行。多線程的意義在於一個應用程序的多個邏輯單元可以併發地執行。但是多線程並不意味着多個用戶進程在執行,操作系統也不把每個線程作爲獨立的進程來分配獨立的系統資源。進程可以創建其子進程,子進程與父進程擁有不同的可執行代碼和數據內存空間。而在用於代表應用程序的進程中多個線程共享數據內存空間,但保持每個線程擁有獨立的執行堆棧和程序執行上下文(Context)。      基於上述區別,線程也可以稱爲輕型進程 (Light Weight Process,LWP)。不同線程間允許任務協作和數據交換,使得在計算機系統資源消耗等方面非常廉價。      線程需要操作系統的支持,不是所有類型的計算機都支持多線程應用程序。Java程序設計語言將線程支持與語言運行環境結合在一起,提供了多任務併發執行的能力。這就好比一個人在處理家務的過程中,將衣服放到洗衣機中自動洗滌後將大米放在電飯鍋裏,然後開始做菜。等菜做好了,飯熟了同時衣服也洗好了。      需要注意的是:在應用程序中使用多線程不會增加 CPU 的數據處理能力。只有在多CPU 的計算機或者在網絡計算體系結構下,將Java程序劃分爲多個併發執行線程後,同時啓動多個線程運行,使不同的線程運行在基於不同處理器的Java虛擬機中,才能提高應用程序的執行效率。 另外,如果應用程序必須等待網絡連接或數據庫連接等數據吞吐速度相對較慢的資源時,多線程應用程序是非常有利的。基於Internet的應用程序有必要是多線程類型的,例如,當開發要支持大量客戶機的服務器端應用程序時,可以將應用程序創建成多線程形式來響應客戶端的連接請求,使每個連接用戶獨佔一個客戶端連接線程。這樣,用戶感覺服務器只爲連接用戶自己服務,從而縮短了服務器的客戶端響應時間。       三、Java語言的多線程程序設計方法         利用Java語言實現多線程應用程序的方法很簡單。根據多線程應用程序繼承或實現對象的不同可以採用兩種方式:一種是應用程序的併發運行對象直接繼承Java的線程類Thread;另外一種方式是定義併發執行對象實現Runnable接口。      繼承Thread類的多線程程序設計方法      Thread 類是JDK中定義的用於控制線程對象的類,在該類中封裝了用於進行線程控制的方法。見下面的示例代碼:      複製代碼 
  • 2009-7-9 18:36
  • 回覆
  • zhutou8033
  • 0位粉絲

2樓

//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();   }   }  
  
              從上面的程序代碼可以看出:多線程執行地下Consumer繼承Java語言中的線程類Thread並且在main方法中創建了三個Consumer對象的實例。當調用對象實例的start方法時,自動調用Consumer類中定義的run方法啓動對象線程運行。線程運行的結果是每間隔nTime時間打印出對象實例中的字符串成員變量strConsumer的內容。      可以總結出繼承Thread類的多線程程序設計方法是使應用程序類繼承Thread類並且在該類的run方法中實現併發性處理過程。      實現Runnable接口的多線程程序設計方法      Java語言中提供的另外一種實現多線程應用程序的方法是多線程對象實現Runnable接口並且在該類中定義用於啓動線程的run方法。這種定義方式的好處在於多線程應用對象可以繼承其它對象而不是必須繼承Thread類,從而能夠增加類定義的邏輯性。      實現Runnable接口的多線程應用程序框架代碼如下所示:      //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();   //其它對象實例的運行線程    //… …    }   }      從上述代碼可以看出:該類實現了Runnable接口並且在該類中定義了run方法。這種多線程應用程序的實現方式與繼承Thread類的多線程應用程序的重要區別在於啓動多線程對象的方法設計方法不同。在上述代碼中,通過創建Thread對象實例並且將應用對象作爲創建Thread類實例的參數。 四、線程間的同步      Java應用程序的多個線程共享同一進程的數據資源,多個用戶線程在併發運行過程中可能同時訪問具有敏感性的內容。在Java中定義了線程同步的概念,實現對共享資源的一致性維護。下面以筆者最近開發的移動通信計費系統中線程間同步控制方法,說明Java語言中多線程同步方式的實現過程。      在沒有多線程同步控制策略條件下的客戶賬戶類定義框架代碼如下所示:      public class RegisterAccount   {   float fBalance;   //客戶繳費方法   public void deposit(float fFees){ fBalance += fFees; }   //通話計費方法   public void withdraw(float fFees){ fBalance -= fFees; }   … …   }               讀者也許會認爲:上述程序代碼完全能夠滿足計費系統實際的需要。確實,在單線程環境下該程序確實是可靠的。但是,多進程併發運行的情況是怎樣的呢?假設發生這種情況:客戶在客戶服務中心進行繳費的同時正在利用移動通信設備僅此通話,客戶通話結束時計費系統啓動計費進程,而同時服務中心的工作人員也提交繳費進程運行。
  • 2009-7-9 18:36
  • 回覆
  • zhutou8033
  • 0位粉絲

3樓

讀者可以看到如果發生這種情況,對客戶賬戶的處理是不嚴肅的。      如何解決這種問題呢?很簡單,在RegisterAccount類方法定義中加上用於標識同步方法的關鍵字synchronized。這樣,在同步方法執行過程中該方法涉及的共享資源(在上述代碼中爲fBalance成員變量)將被加上共享鎖,以確保在方法運行期間只有該方法能夠對共享資源進行訪問,直到該方法的線程運行結束打開共享鎖,其它線程才能夠訪問這些共享資源。在共享鎖沒有打開的時候其它訪問共享資源的線程處於阻塞狀態。      進行線程同步策略控制後的RegisterAccount類定義如下面代碼所示:      public class RegisterAccount   {   float fBalance;   public synchronized void deposit(float fFees){ fBalance += fFees; }   public synchronized void withdraw(float fFees){ fBalance -= fFees; }   … …   }      從經過線程同步機制定義後的代碼形式可以看出:在對共享資源進行訪問的方法訪問屬性關鍵字(public)後附加同步定義關鍵字synchronized,使得同步方法在對共享資源訪問的時候,爲這些敏感資源附加共享鎖來控制方法執行期間的資源獨佔性,實現了應用系統數據資源的一致性管理和維護。 五、 Java線程的管理         線程的狀態控制      在這裏需要明確的是:無論採用繼承Thread類還是實現Runnable接口來實現應用程序的多線程能力,都需要在該類中定義用於完成實際功能的run方法,這個run方法稱爲線程體(Thread Body)。按照線程體在計算機系統內存中的狀態不同,可以將線程分爲創建、就緒、運行、睡眠、掛起和死亡等類型。這些線程狀態類型下線程的特徵爲:      創建狀態:當利用new關鍵字創建線程對象實例後,它僅僅作爲一個對象實例存在,JVM沒有爲其分配CPU時間片等線程運行資源;      就緒狀態:在處於創建狀態的線程中調用start方法將線程的狀態轉換爲就緒狀態。這時,線程已經得到除CPU時間之外的其它系統資源,只等JVM的線程調度器按照線程的優先級對該線程進行調度,從而使該線程擁有能夠獲得CPU時間片的機會。      睡眠狀態:在線程運行過程中可以調用sleep方法並在方法參數中指定線程的睡眠時間將線程狀態轉換爲睡眠狀態。這時,該線程在不釋放佔用資源的情況下停止運行指定的睡眠時間。時間到達後,線程重新由JVM線程調度器進行調度和管理。      掛起狀態:可以通過調用suspend方法將線程的狀態轉換爲掛起狀態。這時,線程將釋放佔用的所有資源,由JVM調度轉入臨時存儲空間,直至應用程序調用resume方法恢復線程運行。      死亡狀態:當線程體運行結束或者調用線程對象的stop方法後線程將終止運行,由JVM收回線程佔用的資源。      在Java線程類中分別定義了相應的方法,用於在應用程序中對線程狀態進行控制和管理。      線程的調度      線程調用的意義在於JVM應對運行的多個線程進行系統級的協調,以避免多個線程爭用有限資源而導致應用系統死機或者崩潰。      爲了線程對於操作系統和用戶的重要性區分開,Java定義了線程的優先級策略。Java將線程的優先級分爲10個等級,分別用1-10之間的數字表示。數字越大表明線程的級別越高。相應地,在Thread類中定義了表示線程最低、最高和普通優先級的成員變量MIN_PRIORITY、MAX_PRIORITY和NORMAL_PRIORITY,代表的優先級等級分別爲1、10和5。當一個線程對象被創建時,其默認的線程優先級是5。      爲了控制線程的運行策略,Java定義了線程調度器來監控系統中處於就緒狀態的所有線程。線程調度器按照線程的優先級決定那個線程投入處理器運行。在多個線程處於就緒狀態的條件下,具有高優先級的線程會在低優先級線程之前得到執行。線程調度器同樣採用"搶佔式"策略來調度線程執行,即當前線程執行過程中有較高優先級的線程進入就緒狀態,則高優先級的線程立即被調度執行。具有相同優先級的所有線程採用輪轉的方式來共同分配CPU時間片。      在應用程序中設置線程優先級的方法很簡單,在創建線程對象之後可以調用線程對象的setPriority方法改變該線程的運行優先級,同樣可以調用getPriority方法獲取當前線程的優先級。      在Java中比較特殊的線程是被稱爲守護(Daemon)線程的低級別線程。這個線程具有最低的優先級,用於爲系統中的其它對象和線程提供服務。將一個用戶線程設置爲守護線程的方式是在線程對象創建之前調用線程對象的setDaemon方法。典型的守護線程例子是JVM中的系統資源自動回收線程,它始終在低級別的狀態中運行,用於實時監控和管理系統中的可回收資源。      線程分組管理      Java定義了在多線程運行系統中的線程組(ThreadGroup)對象,用於實現按照特定功能對線程進行集中式分組管理。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章