進(jìn)程與線程,單核與多核

1. 簡介

用戶打開瀏覽器,其實(shí)就是打開了瀏覽器應(yīng)用程序。那么什么是程序呢?我們常說瀏覽器是多線程的,JS 是單線程的,那么什么是線程呢?說到線程,和我們常說的進(jìn)程有什么關(guān)系?這兩者和程序之間又是什么關(guān)系呢?
為了解答這些疑問,也為了更好地理解瀏覽器的工作原理,我們有必要先學(xué)習(xí)一下程序,進(jìn)程和線程的概念。另外我們還需要了解并行與并發(fā)以及多核與多機(jī)的概念。當(dāng)然,我們只是簡單了解一下這些概念,如果想要深入研究,比如CPU的工作機(jī)制,需要向下看匯編與操作系統(tǒng)的知識,作為淺析階段,這個(gè)系列肯定是不會涉及了。
js是單線程,如何實(shí)現(xiàn)異步?這種異步是不是并發(fā)?瀏覽器如何實(shí)現(xiàn)多線程開發(fā)?

2. 程序

2.1 程序的定義

程序描述計(jì)算機(jī)索要完成的具有獨(dú)立功能的,并在時(shí)間上按嚴(yán)格次序前后相繼的計(jì)算機(jī)操作序列的集合,是一個(gè)靜態(tài)的概念。

2.2 程序的執(zhí)行

程序的執(zhí)行可以分為順序執(zhí)行并發(fā)執(zhí)行。

2.2.1 順序執(zhí)行

把一個(gè)具有獨(dú)立功能的程序獨(dú)占處理機(jī)直到最終結(jié)束的過程稱為順序執(zhí)行。計(jì)算的CPU是通過時(shí)序脈沖來控制執(zhí)行命令的。程序的順序執(zhí)行有以下特點(diǎn)

  • 順序性
    程序順序執(zhí)行時(shí),其執(zhí)行過程可看作一系列嚴(yán)格按照程序規(guī)定的狀態(tài)轉(zhuǎn)移過程,也就是每執(zhí)行一條指令,系統(tǒng)將從上一個(gè)執(zhí)行狀態(tài)轉(zhuǎn)移到下一個(gè)執(zhí)行狀態(tài),且上一條指令的執(zhí)行結(jié)束是下一條指令執(zhí)行開始的充分條件。

  • 封閉性
    程序執(zhí)行的最終結(jié)果由給定的初始條件決定,不受外界因素影響。

  • 可再現(xiàn)性
    程序執(zhí)行的最終結(jié)果可再現(xiàn)。即,與執(zhí)行速度無關(guān),只有初始條件相同,則不論何時(shí)重復(fù)執(zhí)行程序都會得到相同結(jié)果。

2.2.2 并發(fā)執(zhí)行

程序的并發(fā)執(zhí)行是為增加計(jì)算系統(tǒng)的處理能力和提高資源利用率所采用的一種同時(shí)操作技術(shù)。

分為兩種:一種是多道程序系統(tǒng)的程序執(zhí)行環(huán)境變化所引起的多道程序的并發(fā)執(zhí)行,(資源有限,資源的共享與競爭)多道程序的并發(fā)執(zhí)行在宏觀上是同時(shí)進(jìn)行的,但在微觀上(也就是執(zhí)行級上)仍是順序執(zhí)行(單核);一種是某道程序的幾個(gè)程序段中包含著一部分可以同時(shí)執(zhí)行或順序顛倒執(zhí)行的代碼。

程序的并發(fā)執(zhí)行總結(jié)為:一組在邏輯上互相獨(dú)立的程序或程序段在執(zhí)行過程中,其執(zhí)行時(shí)間在客觀上互相重疊。即,一個(gè)程序段的執(zhí)行尚未結(jié)束,另一個(gè)程序段的執(zhí)行已經(jīng)開始的這種執(zhí)行方式。

在許多情況下計(jì)算機(jī)需要能夠同時(shí)處理多個(gè)具有獨(dú)立功能的程序,其執(zhí)行環(huán)境具有以下特點(diǎn)

  • 獨(dú)立性
    邏輯上獨(dú)立,若資源充沛,每道程序都可以獨(dú)立執(zhí)行,執(zhí)行速度與其他程序無關(guān),起止時(shí)間也獨(dú)立。

  • 隨機(jī)性
    程序和數(shù)據(jù)的輸入和執(zhí)行開始時(shí)間都是隨機(jī)的。

  • 資源共享性
    即包括硬件也包括軟件。

程序并發(fā)執(zhí)行的影響:
好處是充分地利用了系統(tǒng)資源,從而提高系統(tǒng)的處理能力;另一方面,由于資源共享和競爭,改變了程序的執(zhí)行速度。一般情況下,并發(fā)執(zhí)行的各程序段如果共享軟、硬件資源,都會造成其執(zhí)行結(jié)果其執(zhí)行速度影響的局面(封閉性和可再現(xiàn)性),為了控制和協(xié)調(diào)各程序段執(zhí)行過程中的軟、硬件資源的共享和競爭,必須應(yīng)該有一個(gè)描述各程序段執(zhí)行過程和共享資源的基本單位,即,進(jìn)程

3. 進(jìn)程

3.1 進(jìn)程的定義

進(jìn)程,是并發(fā)執(zhí)行的程序在執(zhí)行過程中分配和管理資源的基本單位,是一個(gè)動態(tài)概念,竟?fàn)幱?jì)算機(jī)系統(tǒng)資源的基本單位。每一個(gè)進(jìn)程都有一個(gè)自己的地址空間,即進(jìn)程空間。狹義上來理解,可以解釋為正在運(yùn)行的程序的實(shí)例(an instance of a computer program that is being executed)。

3.2 進(jìn)程的特征

進(jìn)程有如下特征:

  • 動態(tài)性
    進(jìn)程的實(shí)質(zhì)是程序在多道程序系統(tǒng)中的一次執(zhí)行過程,進(jìn)程是動態(tài)產(chǎn)生,動態(tài)消亡的。

  • 并發(fā)性
    任何進(jìn)程都可以同其他進(jìn)程一起并發(fā)執(zhí)行。

  • 獨(dú)立性
    進(jìn)程是一個(gè)能獨(dú)立運(yùn)行的基本單位,同時(shí)也是系統(tǒng)分配資源和調(diào)度的獨(dú)立單位。

  • 異步性
    由于進(jìn)程間的相互制約,使進(jìn)程具有執(zhí)行的間斷性,即進(jìn)程按各自獨(dú)立的、不可預(yù)知的速度向前推進(jìn)。

  • 結(jié)構(gòu)特征
    進(jìn)程由程序、數(shù)據(jù)和進(jìn)程控制塊三部分組成。

3.3 進(jìn)程的狀態(tài)

一個(gè)進(jìn)程的生命周期可以劃分為一組狀態(tài),這些狀態(tài)刻畫了整個(gè)進(jìn)程。進(jìn)程狀態(tài)即體現(xiàn)一個(gè)進(jìn)程的生命狀態(tài),反映進(jìn)程執(zhí)行過程的變化。這些狀態(tài)隨著進(jìn)程的執(zhí)行和外界條件的變化而轉(zhuǎn)換。在三態(tài)模型中,進(jìn)程狀態(tài)分為三個(gè)基本狀態(tài),即運(yùn)行態(tài),就緒態(tài),阻塞態(tài)。在五態(tài)模型中,進(jìn)程分為新建態(tài)、終止態(tài),運(yùn)行態(tài),就緒態(tài),阻塞態(tài)。

3.3.1 三態(tài)模型

一個(gè)進(jìn)程從創(chuàng)建而產(chǎn)生至撤銷而消亡的整個(gè)生命期間,有時(shí)占有處理器執(zhí)行,有時(shí)雖可運(yùn)行但分不到處理器、有時(shí)雖有空閑處理器但因等待某個(gè)事件的發(fā)生而無法執(zhí)行,這一切都說明進(jìn)程和程序不相同,它是活動的且有狀態(tài)變化的,這可以用一組狀態(tài)加以刻畫。為了便于管理進(jìn)程,一般來說,按進(jìn)程在執(zhí)行過程中的不同情況至少要定義三種不同的進(jìn)程狀態(tài):

  1. 就緒(ready)態(tài):進(jìn)程具備運(yùn)行條件,等待系統(tǒng)分配處理器以便運(yùn)行。即進(jìn)程已獲得除CPU外的所有必要資源,只等待CPU時(shí)的狀態(tài)。一個(gè)系統(tǒng)會將多個(gè)處于就緒狀態(tài)的進(jìn)程排成一個(gè)就緒隊(duì)列。

  2. 運(yùn)行(running)態(tài):又譯作執(zhí)行態(tài)。進(jìn)程占有處理器正在運(yùn)行。即進(jìn)程已獲CPU,正在執(zhí)行。單處理機(jī)系統(tǒng)中,處于執(zhí)行狀態(tài)的進(jìn)程只一個(gè);多處理機(jī)系統(tǒng)中,有多個(gè)處于執(zhí)行狀態(tài)的進(jìn)程。

  3. 等待(wait)態(tài):又稱為阻塞(blocked)態(tài)或睡眠(sleep)態(tài),指進(jìn)程不具備運(yùn)行條件,正在等待某個(gè)事件的完成。即正在執(zhí)行的進(jìn)程由于某種原因而暫時(shí)無法繼續(xù)執(zhí)行,便放棄處理機(jī)而處于暫停狀態(tài),即進(jìn)程執(zhí)行受阻。

通常,一個(gè)進(jìn)程在創(chuàng)建后將處于就緒狀態(tài)。每個(gè)進(jìn)程在執(zhí)行過程中,任意時(shí)刻當(dāng)且僅當(dāng)處于上述三種狀態(tài)之一。同時(shí),在一個(gè)進(jìn)程執(zhí)行過程中,它的狀態(tài)將會發(fā)生改變。引起進(jìn)程狀態(tài)轉(zhuǎn)換的具體原因如下:

  1. 運(yùn)行態(tài)——等待態(tài):等待使用資源或某事件發(fā)生,如等待外設(shè)傳輸,等待人工干預(yù)。
  2. 等待態(tài)——就緒態(tài):資源得到滿足或某事件己經(jīng)發(fā)生,如外設(shè)傳輸結(jié)束,人工干預(yù)完成。
  3. 運(yùn)行態(tài)——就緒態(tài):運(yùn)行時(shí)間片到,或出現(xiàn)有更高優(yōu)先權(quán)進(jìn)程。
  4. 就緒態(tài)——運(yùn)行態(tài):CPU空閑時(shí)被調(diào)度選中一個(gè)就緒進(jìn)程執(zhí)行。

三態(tài)的轉(zhuǎn)換可以看以下兩張圖,意思其實(shí)是一樣的:


三態(tài)轉(zhuǎn)換1
三態(tài)轉(zhuǎn)換2
3.3.2 五態(tài)模型

在一個(gè)實(shí)際的系統(tǒng)里進(jìn)程的狀態(tài)及其轉(zhuǎn)換比上節(jié)敘述的復(fù)雜一些,例如,引入專門的新建態(tài)(new)和終止態(tài)(exit )。

  1. 新建(new)態(tài):又譯作創(chuàng)建態(tài)。新建態(tài)對應(yīng)于進(jìn)程剛剛被創(chuàng)建的狀態(tài),創(chuàng)建一個(gè)進(jìn)程要通過兩個(gè)步驟,首先,是為一個(gè)新進(jìn)程創(chuàng)建PCB,并填寫必要管理信息;然后,讓該進(jìn)程進(jìn)入就緒態(tài)。此時(shí)進(jìn)程將處于新建態(tài),它并沒有被提交執(zhí)行,而是在等待操作系統(tǒng)完成創(chuàng)建進(jìn)程的必要操作。必須指出的是,操作系統(tǒng)有時(shí)將根據(jù)系統(tǒng)性能或主存容量的限制推遲新建態(tài)進(jìn)程的提交。

  2. 終止(exit)態(tài):進(jìn)程的終止也要通過兩個(gè)步驟,首先,是等待操作系統(tǒng)進(jìn)行善后;然后,退出主存。當(dāng)一個(gè)進(jìn)程到達(dá)了自然結(jié)束點(diǎn),或是出現(xiàn)了無法克服的錯(cuò)誤,或是被操作系統(tǒng)所終結(jié),或是被其他有終止權(quán)的進(jìn)程所終結(jié),它將進(jìn)入終止態(tài)。進(jìn)入終止態(tài)的進(jìn)程以后不再執(zhí)行,但依然保留在操作系統(tǒng)中等待善后。一旦其他進(jìn)程完成了對終止態(tài)進(jìn)程的信息抽取之后,操作系統(tǒng)將刪除該進(jìn)程。

引起進(jìn)程狀態(tài)轉(zhuǎn)換的具體原因如下:

  1. NULL——新建態(tài): 執(zhí)行一個(gè)程序,創(chuàng)建一個(gè)子進(jìn)程。
  2. 新建態(tài)——就緒態(tài): 當(dāng)操作系統(tǒng)完成了進(jìn)程創(chuàng)建的必要操作,并且當(dāng)前系統(tǒng)的性能和內(nèi)存的容量均允許。
  3. 運(yùn)行態(tài)——終止態(tài): 當(dāng)一個(gè)進(jìn)程到達(dá)了自然結(jié)束點(diǎn),或是出現(xiàn)了無法克服的錯(cuò)誤,或是被操作系統(tǒng)所終結(jié),或是被其他有終止權(quán)的進(jìn)程所終結(jié)。
  4. 終止態(tài)——NULL: 完成善后操作。
  5. 就緒態(tài)——終止態(tài): 未在狀態(tài)轉(zhuǎn)換圖中顯示,但某些操作系統(tǒng)允許父進(jìn)程終結(jié)子進(jìn)程。
  6. 等待態(tài)——終止態(tài): 未在狀態(tài)轉(zhuǎn)換圖中顯示,但某些操作系統(tǒng)允許父進(jìn)程終結(jié)子進(jìn)程。

五態(tài)的轉(zhuǎn)換可以看下面這張圖:


五態(tài)轉(zhuǎn)換
3.3.3 狀態(tài)控制
  1. 進(jìn)程創(chuàng)建
    每個(gè)進(jìn)程都有生命期,即從創(chuàng)建到消亡的時(shí)間周期。當(dāng)操作系統(tǒng)為一個(gè)程序構(gòu)造一個(gè)進(jìn)程控制塊并分配地址空間之后,就創(chuàng)建了一個(gè)進(jìn)程。進(jìn)程的創(chuàng)建來源于以下四個(gè)事件:
    (1)提交個(gè)批處理作業(yè)。
    (2)在終端上個(gè)交互式作業(yè)登錄。
    (3)操作系統(tǒng)創(chuàng)建‘個(gè)服務(wù)進(jìn)程。
    (4)存在的進(jìn)程創(chuàng)建新的進(jìn)程。

  2. 進(jìn)程的阻塞和喚醒
    進(jìn)程的阻塞是指使一個(gè)進(jìn)程讓出處理器,去等待一個(gè)事件,如等待資源、等待I/O完成、等待一個(gè)事件發(fā)生等,通常進(jìn)程自己調(diào)用阻塞原語阻塞自己,所以,是進(jìn)程自主行為,是一個(gè)同步事件。當(dāng)一個(gè)等待事件結(jié)束會產(chǎn)生一個(gè)中斷,從而,激活操作系統(tǒng),在系統(tǒng)的控制之下將被阻塞的進(jìn)程喚醒,如I/O操作結(jié)束、某個(gè)資源可用或期待事件出現(xiàn)。進(jìn)程的阻塞和喚醒顯然是由進(jìn)程切換來完成。

  3. 進(jìn)程的撤銷
    一個(gè)進(jìn)程完成了特定的工作或出現(xiàn)了嚴(yán)重的異常后,操作系統(tǒng)則收回它占有的地址空間和進(jìn)程控制塊,此時(shí)就說撤銷了一個(gè)進(jìn)程。進(jìn)程撤銷可以分正常和非正常撤銷,前者如分時(shí)系統(tǒng)中的注消和批處理系統(tǒng)中的撤離作業(yè)步,后者如進(jìn)程運(yùn)行過程中出現(xiàn)錯(cuò)誤與異常。

  4. 進(jìn)程的掛起和激活
    當(dāng)出現(xiàn)了引起掛起的事件時(shí)系統(tǒng)或進(jìn)程利用掛起原語把指定進(jìn)程或處于阻塞狀態(tài)的進(jìn)程掛起。其執(zhí)行過程大致如下:檢查要被掛起進(jìn)程的狀態(tài),若處于活動就緒態(tài)就修改為掛起就緒,若處于阻塞態(tài),則修改為掛起阻塞。被掛起進(jìn)程PCB的非常駐部分要交換到磁盤對換區(qū)。
    當(dāng)系統(tǒng)資源尤其是內(nèi)存資源充?;蜻M(jìn)程請求激活指定進(jìn)程時(shí),系統(tǒng)或有關(guān)進(jìn)程會調(diào)用激活原語把指定進(jìn)程激活,該原語所做的主要工作是:把進(jìn)程PCB非常駐部分調(diào)進(jìn)內(nèi)存,然后修改它的狀態(tài),掛起等待態(tài)改為等待態(tài),掛起就緒態(tài)改為就緒態(tài),并分別排入相應(yīng)隊(duì)列中。

可以參考下圖:


3.4 進(jìn)程和程序的區(qū)別和聯(lián)系:

  1. 進(jìn)程是一個(gè)動態(tài)概念,而程序是一個(gè)靜態(tài)的概念。程序是指令的有序集合,沒有任何執(zhí)行的意義,而進(jìn)程則強(qiáng)調(diào)執(zhí)行過程,它動態(tài)被創(chuàng)建,并被調(diào)度執(zhí)行消亡。

  2. 進(jìn)程具有并發(fā)特點(diǎn)。進(jìn)程具有并發(fā)特征的兩個(gè)方面:獨(dú)立性和異步性——不考慮資源的情況下,各進(jìn)程的執(zhí)行是獨(dú)立的,速度是異步的,而程序沒有并發(fā)特征。

  3. 進(jìn)程是競爭計(jì)算系統(tǒng)資源的基本單位,從而其并發(fā)性受到系統(tǒng)自己的制約,這里,制約就是對程序獨(dú)立性和異步性的限制。

  4. 一個(gè)程序可對應(yīng)多個(gè)進(jìn)程,也就是說同一程序同時(shí)運(yùn)行于若干個(gè)數(shù)據(jù)集合上,它屬于若干個(gè)不同的進(jìn)程。但是程序并不能獨(dú)立運(yùn)行,作為資源分配和獨(dú)立運(yùn)行的基本單元都是進(jìn)程。 一個(gè)進(jìn)程可以對應(yīng)多個(gè)程序。

一個(gè)更有意思的解釋可以參考這篇文章:進(jìn)程和程序(Process and Program)

4. 線程

4.1 線程的定義

線程的出現(xiàn)是為了降低上下文切換的消耗,提高系統(tǒng)的并發(fā)性,并突破一個(gè)進(jìn)程只能干一樣事的缺陷,使到進(jìn)程內(nèi)并發(fā)成為可能。

假設(shè),一個(gè)文本程序,需要接受鍵盤輸入,將內(nèi)容顯示在屏幕上,還需要保存信息到硬盤中。若只有一個(gè)進(jìn)程,勢必造成同一時(shí)間只能干一樣事的尷尬(當(dāng)保存時(shí),就不能通過鍵盤輸入內(nèi)容)。若有多個(gè)進(jìn)程,每個(gè)進(jìn)程負(fù)責(zé)一個(gè)任務(wù),進(jìn)程A負(fù)責(zé)接收鍵盤輸入的任務(wù),進(jìn)程B負(fù)責(zé)將內(nèi)容顯示在屏幕上的任務(wù),進(jìn)程C負(fù)責(zé)保存內(nèi)容到硬盤中的任務(wù)。這里進(jìn)程A,B,C間的協(xié)作涉及到了進(jìn)程通信問題,而且有共同都需要擁有的東西——-文本內(nèi)容,不停的切換造成性能上的損失。若有一種機(jī)制,可以使任務(wù)A,B,C共享資源,這樣上下文切換所需要保存和恢復(fù)的內(nèi)容就少了,同時(shí)又可以減少通信所帶來的性能損耗,那就好了。是的,這種機(jī)制就是線程。

線程也叫輕量級進(jìn)程,它是一個(gè)基本的CPU執(zhí)行單元,也是程序執(zhí)行過程中的最小單元,由線程ID、程序計(jì)數(shù)器、寄存器集合和堆棧共同組成。線程的引入減小了程序并發(fā)執(zhí)行時(shí)的開銷,提高了操作系統(tǒng)的并發(fā)性能。線程沒有自己的系統(tǒng)資源,只擁有一點(diǎn)兒在運(yùn)行中必不可少的資源,但它可與同屬一個(gè)進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源。一個(gè)線程可以創(chuàng)建和撤消另一個(gè)線程,同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行。

4.2 線程的特征

在多線程OS中,通常是在一個(gè)進(jìn)程中包括多個(gè)線程,每個(gè)線程都是作為利用CPU的基本單位,是花費(fèi)最小開銷的實(shí)體。線程具有以下屬性。

  1. 輕型實(shí)體
    線程中的實(shí)體基本上不擁有系統(tǒng)資源,只是有一點(diǎn)必不可少的、能保證獨(dú)立運(yùn)行的資源。
    線程的實(shí)體包括程序、數(shù)據(jù)和TCB。線程是動態(tài)概念,它的動態(tài)特性由線程控制塊TCB(Thread Control Block)描述。TCB包括以下信息:
    (1)線程狀態(tài)。
    (2)當(dāng)線程不運(yùn)行時(shí),被保存的現(xiàn)場資源。
    (3)一組執(zhí)行堆棧。
    (4)存放每個(gè)線程的局部變量主存區(qū)。
    (5)訪問同一個(gè)進(jìn)程中的主存和其它資源。
    用于指示被執(zhí)行指令序列的程序計(jì)數(shù)器、保留局部變量、少數(shù)狀態(tài)參數(shù)和返回地址等的一組寄存器和堆棧。

  2. 獨(dú)立調(diào)度和分派的基本單位
    在多線程OS中,線程是能獨(dú)立運(yùn)行的基本單位,因而也是獨(dú)立調(diào)度和分派的基本單位。由于線程很“輕”,故線程的切換非常迅速且開銷?。ㄔ谕贿M(jìn)程中的)。

  3. 可并發(fā)執(zhí)行
    在一個(gè)進(jìn)程中的多個(gè)線程之間,可以并發(fā)執(zhí)行,甚至允許在一個(gè)進(jìn)程中所有線程都能并發(fā)執(zhí)行;同樣,不同進(jìn)程中的線程也能并發(fā)執(zhí)行,充分利用和發(fā)揮了處理機(jī)與外圍設(shè)備并行工作的能力。

  4. 共享進(jìn)程資源
    在同一進(jìn)程中的各個(gè)線程,都可以共享該進(jìn)程所擁有的資源,這首先表現(xiàn)在:所有線程都具有相同的地址空間(進(jìn)程的地址空間),這意味著,線程可以訪問該地址空間的每一個(gè)虛地址;此外,還可以訪問進(jìn)程所擁有的已打開文件、定時(shí)器、信號量機(jī)構(gòu)等。由于同一個(gè)進(jìn)程內(nèi)的線程共享內(nèi)存和文件,所以線程之間互相通信不必調(diào)用內(nèi)核。

4.3 線程的狀態(tài)

線程從創(chuàng)建、運(yùn)行到結(jié)束總是處于下面五個(gè)狀態(tài)之一:新建狀態(tài)、就緒狀態(tài)、運(yùn)行狀態(tài)、阻塞狀態(tài)及死亡狀態(tài)。

  1. 新建狀態(tài)(New Thread)
    產(chǎn)生一個(gè)Thread對象就生成一個(gè)新線程。當(dāng)線程處于"新線程"狀態(tài)時(shí),僅僅是一個(gè)空線程對象,它還沒有分配到系統(tǒng)資源。因此只能啟動或終止它。任何其他操作都會引發(fā)異常。例如,一個(gè)線程調(diào)用了new方法之后,并在調(diào)用start方法之前的處于新線程狀態(tài),可以調(diào)用start和stop方法。

  2. 就緒狀態(tài)(Runnable)
    start()方法產(chǎn)生運(yùn)行線程所必須的資源,調(diào)度線程執(zhí)行,并且調(diào)用線程的run()方法。在這時(shí)線程處于就緒狀態(tài)。該狀態(tài)不稱為運(yùn)行態(tài)是因?yàn)檫@時(shí)的線程并不總是一直占用處理機(jī)。特別是對于只有一個(gè)處理機(jī)的PC而言,任何時(shí)刻只能有一個(gè)處于就緒態(tài)的線程占用處理機(jī)。Java通過調(diào)度來實(shí)現(xiàn)多線程對處理機(jī)的共享。注意,如果線程處于Runnable狀態(tài),它也有可能不在運(yùn)行,這是因?yàn)檫€有優(yōu)先級和調(diào)度問題。

  3. 運(yùn)行狀態(tài)(Running)
    當(dāng)線程獲得CPU時(shí)間后,它才進(jìn)入運(yùn)行狀態(tài),真正開始執(zhí)行run()方法。

  4. 阻塞狀態(tài)(Blocked)
    所謂阻塞狀態(tài)是正在運(yùn)行的線程沒有運(yùn)行結(jié)束,暫時(shí)讓出CPU,這時(shí)其他處于就緒狀態(tài)的線程就可以獲得CPU時(shí)間,進(jìn)入運(yùn)行狀態(tài)。
    阻塞狀態(tài)分為三種:
    1、等待阻塞:運(yùn)行的線程執(zhí)行wait()方法,JVM會把該線程放入等待池中。
    2、同步阻塞:運(yùn)行的線程在獲取對象同步鎖時(shí),若該同步鎖被別的線程占用,則JVM會把線程放入鎖池中。
    3、其他阻塞:運(yùn)行的線程執(zhí)行Sleep()方法,或者發(fā)出I/O請求時(shí),JVM會把線程設(shè)為阻塞狀態(tài)。當(dāng)Sleep()狀態(tài)超時(shí)、或者I/O處理完畢時(shí),線程重新轉(zhuǎn)入就緒狀態(tài)。
    線程運(yùn)行過程中,可能由于各種原因進(jìn)入阻塞狀態(tài):
    ①線程通過調(diào)用sleep方法進(jìn)入睡眠狀態(tài);
    ②線程調(diào)用一個(gè)在I/O上被阻塞的操作,即該操作在輸入輸出操作完成之前不會返回到它的調(diào)用者;
    ③線程試圖得到一個(gè)鎖,而該鎖正被其他線程持有;
    ④線程在等待某個(gè)觸發(fā)條件;
    具體來講,線程被堵塞可能是由下述五個(gè)方法造成的:
    (1) 調(diào)用sleep(毫秒數(shù)),使線程進(jìn)入"睡眠"狀態(tài)。在規(guī)定的時(shí)間內(nèi),這個(gè)線程是不會運(yùn)行的。
    (2) 用suspend()暫停了線程的執(zhí)行。除非線程收到resume()消息,否則不會返回"可運(yùn)行"狀態(tài)。
    (3) 用wait()暫停了線程的執(zhí)行。除非線程收到nofify()或者notifyAll()消息,否則不會變成"可運(yùn)行"(是的,這看起來同原因2非常相象,但有一個(gè)明顯的區(qū)別是我們馬上要揭示的)。
    (4) 線程正在等候一些IO(輸入輸出)操作完成。
    (5) 線程試圖調(diào)用另一個(gè)對象的"同步"方法,但那個(gè)對象處于鎖定狀態(tài),暫時(shí)無法使用。

  5. 死亡狀態(tài)(Dead)
    當(dāng)線程執(zhí)行完run()方法中的代碼,或別的線程調(diào)用stop()方法,或者遇到了未捕獲的異常,就會退出run()方法,此時(shí)就進(jìn)入死亡狀態(tài),該線程結(jié)束生命周期。通常Applet使用它的stop()方法來終止它產(chǎn)生的所有線程。
    為了確定線程在當(dāng)前是否存活著(就是要么是可運(yùn)行的,要么是被阻塞了),需要使用isAlive方法,如果是可運(yùn)行或被阻塞,這個(gè)方法返回true;如果線程仍舊是new狀態(tài)且不是可運(yùn)行的,或者線程死亡了,則返回false。

可以參考下圖:


線程狀態(tài)

詳細(xì)地狀態(tài)轉(zhuǎn)換可以參考這里線程的幾種狀態(tài)轉(zhuǎn)換。

4.4 線程和進(jìn)程的關(guān)系和區(qū)別

進(jìn)程和線程的關(guān)系:
(1)一個(gè)線程只能屬于一個(gè)進(jìn)程,而一個(gè)進(jìn)程可以有多個(gè)線程,至少有一個(gè)線程。
(2)資源分配給進(jìn)程,同一進(jìn)程的所有線程共享該進(jìn)程的所有資源。
(3)處理機(jī)分給線程,即真正在處理機(jī)上運(yùn)行的是線程。
(4)線程在執(zhí)行過程中,需要協(xié)作同步。不同進(jìn)程的線程間要利用消息通信的辦法實(shí)現(xiàn)同步。線程是指進(jìn)程內(nèi)的一個(gè)執(zhí)行單元,也是進(jìn)程內(nèi)的可調(diào)度實(shí)體.

進(jìn)程與線程的區(qū)別:
(1)調(diào)度:線程作為調(diào)度和分配的基本單位,進(jìn)程作為擁有資源的基本單位
(2)并發(fā)性:不僅進(jìn)程之間可以并發(fā)執(zhí)行,同一個(gè)進(jìn)程的多個(gè)線程之間也可并發(fā)執(zhí)行
(3)擁有資源:進(jìn)程是擁有資源的一個(gè)獨(dú)立單位,線程不擁有系統(tǒng)資源,但可以訪問隸屬于進(jìn)程的資源.
(4)系統(tǒng)開銷:在創(chuàng)建或撤消進(jìn)程時(shí),由于系統(tǒng)都要為之分配和回收資源,導(dǎo)致系統(tǒng)的開銷明顯大于創(chuàng)建或撤消線程時(shí)的開銷。

5. 多進(jìn)程與多線程的選擇

5.1并行與并發(fā)

并發(fā)處理(concurrency Processing):指一個(gè)時(shí)間段中有幾個(gè)程序都處于已啟動運(yùn)行到運(yùn)行完畢之間,且這幾個(gè)程序都是在同一個(gè)處理機(jī)(CPU)上運(yùn)行,但任一個(gè)時(shí)刻點(diǎn)上只有一個(gè)程序在處理機(jī)(CPU)上運(yùn)行。當(dāng)有多個(gè)線程在操作時(shí),如果系統(tǒng)只有一個(gè)CPU,則它根本不可能真正同時(shí)進(jìn)行一個(gè)以上的線程,它只能把CPU運(yùn)行時(shí)間劃分成若干個(gè)時(shí)間段,再將時(shí)間 段分配給各個(gè)線程執(zhí)行,在一個(gè)時(shí)間段的線程代碼運(yùn)行時(shí),其它線程處于掛起狀。這種方式我們稱之為并發(fā)(Concurrent)。

并行:當(dāng)系統(tǒng)有一個(gè)以上CPU時(shí),則線程的操作有可能非并發(fā)。當(dāng)一個(gè)CPU執(zhí)行一個(gè)線程時(shí),另一個(gè)CPU可以執(zhí)行另一個(gè)線程,兩個(gè)線程互不搶占CPU資源,可以同時(shí)進(jìn)行,這種方式我們稱之為并行(Parallel)。并行處理(Parallel Processing)是計(jì)算機(jī)系統(tǒng)中能同時(shí)執(zhí)行兩個(gè)或更多個(gè)處理的一種計(jì)算方法。并行處理可同時(shí)工作于同一程序的不同方面。并行處理的主要目的是節(jié)省大型和復(fù)雜問題的解決時(shí)間。

并發(fā)的關(guān)鍵是你有處理多個(gè)任務(wù)的能力,不一定要同時(shí)。并行的關(guān)鍵是你有同時(shí)處理多個(gè)任務(wù)的能力。所以說,并行是并發(fā)的子集。

串行,并行,并發(fā)

5.2 多核與多機(jī)

  • 多處理機(jī)(SMP):
  1. 多個(gè)物理cpu
  2. 每個(gè)cpu有自己的獨(dú)立cache、寄存器、運(yùn)算單元。
  3. 每個(gè)cpu對內(nèi)存的訪問速度一樣。
  • 多核cpu (雙核)
  1. 一個(gè)物理cpu包含多個(gè)cpu核心。
  2. 每個(gè)核心有自己的獨(dú)立寄存器和運(yùn)算單元。
  3. 可共享最后一級cache。
  • 多線程cpu (雙核四線程)
  1. 一個(gè)物理cpu包含多個(gè)邏輯cpu;這些邏輯cpu有自己的通用寄存器。
  2. 共享cache和運(yùn)算單元(邏輯cpu)。
  3. 由于cpu通常包含多個(gè)運(yùn)算單元,因此多線程cpu實(shí)際可同時(shí)運(yùn)行。

5.3 多進(jìn)程與多線程

5.3.1 多進(jìn)程與多線程的優(yōu)勢對比
多進(jìn)程與多線程的對比
5.3.2進(jìn)程之間,線程之間的通信方式以及優(yōu)缺點(diǎn)

進(jìn)程之間的通信:
1)管道
管道分為有名管道和無名管道
無名管道是一種半雙工的通信方式,數(shù)據(jù)只能單向流動,而且只能在具有親緣關(guān)系的進(jìn)程間使用.進(jìn)程的親緣關(guān)系一般指的是父子關(guān)系。無明管道一般用于兩個(gè)不同進(jìn)程之間的通信。當(dāng)一個(gè)進(jìn)程創(chuàng)建了一個(gè)管道,并調(diào)用fork創(chuàng)建自己的一個(gè)子進(jìn)程后,父進(jìn)程關(guān)閉讀管道端,子進(jìn)程關(guān)閉寫管道端,這樣提供了兩個(gè)進(jìn)程之間數(shù)據(jù)流動的一種方式。
有名管道也是一種半雙工的通信方式,但是它允許無親緣關(guān)系進(jìn)程間的通信。

無名管道:
優(yōu)點(diǎn):簡單方便;
缺點(diǎn):1)局限于單向通信2)只能創(chuàng)建在它的進(jìn)程以及其有親緣關(guān)系的進(jìn)程之間;3)緩沖區(qū)有限;
有名管道:
優(yōu)點(diǎn):可以實(shí)現(xiàn)任意關(guān)系的進(jìn)程間的通信;
缺點(diǎn):1)長期存于系統(tǒng)中,使用不當(dāng)容易出錯(cuò);2)緩沖區(qū)有限

2)信號量
信號量是一個(gè)計(jì)數(shù)器,可以用來控制多個(gè)線程對共享資源的訪問.,它不是用于交換大批數(shù)據(jù),而用于多線程之間的同步.它常作為一種鎖機(jī)制,防止某進(jìn)程在訪問資源時(shí)其它進(jìn)程也訪問該資源.因此,主要作為進(jìn)程間以及同一個(gè)進(jìn)程內(nèi)不同線程之間的同步手段.

優(yōu)點(diǎn):可以同步進(jìn)程;
缺點(diǎn):信號量有限

3)信號
信號是一種比較復(fù)雜的通信方式,用于通知接收進(jìn)程某個(gè)事件已經(jīng)發(fā)生.

4)消息隊(duì)列
消息隊(duì)列是消息的鏈表,存放在內(nèi)核中并由消息隊(duì)列標(biāo)識符標(biāo)識.消息隊(duì)列克服了信號傳遞信息少,管道只能承載無格式字節(jié)流以及緩沖區(qū)大小受限等特點(diǎn).消息隊(duì)列是UNIX下不同進(jìn)程之間可實(shí)現(xiàn)共享資源的一種機(jī)制,UNIX允許不同進(jìn)程將格式化的數(shù)據(jù)流以消息隊(duì)列形式發(fā)送給任意進(jìn)程.對消息隊(duì)列具有操作權(quán)限的進(jìn)程都可以使用msget完成對消息隊(duì)列的操作控制.通過使用消息類型,進(jìn)程可以按任何順序讀信息,或?yàn)橄才艃?yōu)先級順序.

優(yōu)點(diǎn):可以實(shí)現(xiàn)任意進(jìn)程間的通信,并通過系統(tǒng)調(diào)用函數(shù)來實(shí)現(xiàn)消息發(fā)送和接收之間的同步,無需考慮同步問題,方便;
缺點(diǎn):信息的復(fù)制需要額外消耗CPU的時(shí)間,不適宜于信息量大或操作頻繁的場合

5)共享內(nèi)存
共享內(nèi)存就是映射一段能被其他進(jìn)程所訪問的內(nèi)存,這段共享內(nèi)存由一個(gè)進(jìn)程創(chuàng)建,但多個(gè)進(jìn)程都可以訪問.共享內(nèi)存是最快的IPC(進(jìn)程間通信)方式,它是針對其它進(jìn)程間通信方式運(yùn)行效率低而專門設(shè)計(jì)的.它往往與其他通信機(jī)制,如信號量,配合使用,來實(shí)現(xiàn)進(jìn)程間的同步與通信.

優(yōu)點(diǎn):無須復(fù)制,快捷,信息量大;
缺點(diǎn):1)通信是通過將共無法實(shí)現(xiàn)享空間緩沖區(qū)直接附加到進(jìn)程的虛擬地址空間中來實(shí)現(xiàn)的,因此進(jìn)程間的讀寫操作的同步問題;2)利用內(nèi)存緩沖區(qū)直接交換信息,內(nèi)存的實(shí)體存在于計(jì)算機(jī)中,只能同一個(gè)計(jì)算機(jī)系統(tǒng)中的諸多進(jìn)程共享,不方便網(wǎng)絡(luò)通信

6)套接字:可用于不同及其間的進(jìn)程通信
優(yōu)點(diǎn):1)傳輸數(shù)據(jù)為字節(jié)級,傳輸數(shù)據(jù)可自定義,數(shù)據(jù)量小效率高;2)傳輸數(shù)據(jù)時(shí)間短,性能高;3) 適合于客戶端和服務(wù)器端之間信息實(shí)時(shí)交互;4) 可以加密,數(shù)據(jù)安全性強(qiáng)
缺點(diǎn):1) 需對傳輸?shù)臄?shù)據(jù)進(jìn)行解析,轉(zhuǎn)化成應(yīng)用級的數(shù)據(jù)。

線程之間的通信方式:

  • 鎖機(jī)制:包括互斥鎖、條件變量、讀寫鎖
    • 互斥鎖提供了以排他方式防止數(shù)據(jù)結(jié)構(gòu)被并發(fā)修改的方法。
    • 讀寫鎖允許多個(gè)線程同時(shí)讀共享數(shù)據(jù),而對寫操作是互斥的。
    • 條件變量可以以原子的方式阻塞進(jìn)程,直到某個(gè)特定條件為真為止。對條件的測試是在互斥鎖的保護(hù)下進(jìn)行的。條件變量始終與互斥鎖一起使用。
  • 信號量機(jī)制(Semaphore):包括無名線程信號量和命名線程信號量
  • 信號機(jī)制(Signal):類似進(jìn)程間的信號處理

線程間的通信目的主要是用于線程同步,所以線程沒有像進(jìn)程通信中的用于數(shù)據(jù)交換的通信機(jī)制。

5.3.3 多進(jìn)程與多線程的選擇
  1. 需要頻繁創(chuàng)建銷毀的優(yōu)先用線程
    原因請看上面的對比。
    這種原則最常見的應(yīng)用就是Web服務(wù)器了,來一個(gè)連接建立一個(gè)線程,斷了就銷毀線程,要是用進(jìn)程,創(chuàng)建和銷毀的代價(jià)是很難承受的

  2. 需要進(jìn)行大量計(jì)算的優(yōu)先使用線程
    所謂大量計(jì)算,當(dāng)然就是要耗費(fèi)很多CPU,切換頻繁了,這種情況下線程是最合適的。
    這種原則最常見的是圖像處理、算法處理。

  3. 強(qiáng)相關(guān)的處理用線程,弱相關(guān)的處理用進(jìn)程
    什么叫強(qiáng)相關(guān)、弱相關(guān)?理論上很難定義,給個(gè)簡單的例子就明白了。
    一般的Server需要完成如下任務(wù):消息收發(fā)、消息處理。“消息收發(fā)”和“消息處理”就是弱相關(guān)的任務(wù),而“消息處理”里面可能又分為“消息解碼”、“業(yè)務(wù)處理”,這兩個(gè)任務(wù)相對來說相關(guān)性就要強(qiáng)多了。因此“消息收發(fā)”和“消息處理”可以分進(jìn)程設(shè)計(jì),“消息解碼”、“業(yè)務(wù)處理”可以分線程設(shè)計(jì)。
    當(dāng)然這種劃分方式不是一成不變的,也可以根據(jù)實(shí)際情況進(jìn)行調(diào)整。

  4. 可能要擴(kuò)展到多機(jī)分布的用進(jìn)程,多核分布的用線程
    原因請看上面對比。

  5. 都滿足需求的情況下,用你最熟悉、最拿手的方式
    至于“數(shù)據(jù)共享、同步”、“編程、調(diào)試”、“可靠性”這幾個(gè)維度的所謂的“復(fù)雜、簡單”應(yīng)該怎么取舍,我只能說:沒有明確的選擇方法。但我可以告訴你一個(gè)選擇原則:如果多進(jìn)程和多線程都能夠滿足要求,那么選擇你最熟悉、最拿手的那個(gè)。

需要提醒的是:雖然有如此多選擇與比較原則,但實(shí)際應(yīng)用中基本上都是“進(jìn)程+線程”的結(jié)合方式,千萬不要真的陷入一種非此即彼的誤區(qū)。

6. 小結(jié)

以上這些知識,其實(shí)是為了我們后續(xù)的講解做鋪墊,如果大家覺得很繁冗。可以歸直接記住以下幾點(diǎn):

  1. 瀏覽器本身是一個(gè)程序,當(dāng)我們運(yùn)行它,操作學(xué)習(xí)通就開啟了瀏覽器相關(guān)的進(jìn)程。
  2. 瀏覽器進(jìn)程里面包含了若干的線程。
  3. 一個(gè)核心同一時(shí)間只能處理一個(gè)線程,不過可以通過時(shí)間分片來實(shí)現(xiàn)多任務(wù)的并發(fā),多核可以達(dá)成真正意義的并行。另外超線程技術(shù)通過邏輯CPU模擬核心達(dá)到并行,但是實(shí)際能力會弱于多核。

當(dāng)然,作為一個(gè)前端開發(fā)者,你并不需要關(guān)心,你的線程會被分配給哪一個(gè)核心處理,這個(gè)會由操作系統(tǒng)根據(jù)一定算法進(jìn)行調(diào)度。這些內(nèi)容是為了下一階段知識做鋪墊而已,理解了這些,我們才能去探索為何我們說js是單線程的,但是卻可以實(shí)現(xiàn)異步,在處理邏輯的時(shí)候還能進(jìn)行請求操作等現(xiàn)象背后的原因。

參考

進(jìn)程的概念
進(jìn)程狀態(tài)-百度百科
進(jìn)程三種基本狀態(tài)
進(jìn)程五種基本狀態(tài)
程序、進(jìn)程和線程的關(guān)系
線程-百度百科
進(jìn)程-百度百科
多線程—線程的5種狀態(tài)
線程的基本概念、線程的基本狀態(tài)以及狀態(tài)之間的關(guān)系
多線程與多進(jìn)程
進(jìn)程與線程的區(qū)別-百度經(jīng)驗(yàn)
進(jìn)程和線程的區(qū)別以及聯(lián)系
基礎(chǔ)知識:線程,進(jìn)程。多進(jìn)程,多線程。并發(fā),并行的區(qū)別
多處理機(jī)、多核cpu、多線程cpu的區(qū)別
多線程還是多進(jìn)程的選擇及區(qū)別
進(jìn)程線程面試題總結(jié)

線程和進(jìn)程的區(qū)別是什么?
進(jìn)程上下文和中斷上下文
多進(jìn)程和多線程的優(yōu)缺點(diǎn)
進(jìn)程與線程的一個(gè)簡單解釋
深入理解javascript異步編程障眼法&&h5 web worker實(shí)現(xiàn)多線程
淺談多核CPU、多線程與并行計(jì)算
處理器關(guān)于多核概念與區(qū)別 多核處理器工作原理及優(yōu)缺點(diǎn)
對于多線程程序,單核cpu與多核cpu是怎么工作的
cpu個(gè)數(shù)、核數(shù)、線程數(shù)、Java多線程關(guān)系的理解
單核處理器、多核處理器、多處理器與多線程編程

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 又來到了一個(gè)老生常談的問題,應(yīng)用層軟件開發(fā)的程序員要不要了解和深入學(xué)習(xí)操作系統(tǒng)呢? 今天就這個(gè)問題開始,來談?wù)劜?..
    tangsl閱讀 4,322評論 0 23
  • 1.內(nèi)存的頁面置換算法 (1)最佳置換算法(OPT)(理想置換算法):從主存中移出永遠(yuǎn)不再需要的頁面;如無這樣的...
    杰倫哎呦哎呦閱讀 3,596評論 1 9
  • 有沒有這樣的經(jīng)歷,悄悄的翻看一個(gè)人的朋友圈,從第一條到最后一條動態(tài),從來沒有過的耐心細(xì)致。 希望從那些細(xì)枝末節(jié)之中...
    趙不棄閱讀 275評論 0 1
  • 在這個(gè)信息化時(shí)代,網(wǎng)絡(luò)資源真的很豐富,但是我們老師找到合適的資源卻還是要費(fèi)些功夫的。平常上課時(shí),我總會竭...
    大名411井博麗閱讀 540評論 2 0
  • WPS有適合各類系統(tǒng)的版本,注冊帳號可以方便的同步文件,實(shí)現(xiàn)多平臺編輯,使用場景也越來越多,但WPS在方便我們工作...
    月夜紫荊閱讀 997評論 6 3

友情鏈接更多精彩內(nèi)容