日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

線(xiàn)程同步 [轉(zhuǎn)]

 昵稱(chēng)15515903 2014-08-14

線(xiàn)程同步 [轉(zhuǎn)]  
我們可以在計(jì)算機(jī)上運(yùn)行各種計(jì)算機(jī)軟件程序。每一個(gè)運(yùn)行的程序可能包括多個(gè)獨(dú)立運(yùn)行的線(xiàn)程(Thread)。
線(xiàn)程(Thread)是一份獨(dú)立運(yùn)行的程序,有自己專(zhuān)用的運(yùn)行棧。線(xiàn)程有可能和其他線(xiàn)程共享一些資源,比如,內(nèi)存,文件,數(shù)據(jù)庫(kù)等。
當(dāng)多個(gè)線(xiàn)程同時(shí)讀寫(xiě)同一份共享資源的時(shí)候,可能會(huì)引起沖突。這時(shí)候,我們需要引入線(xiàn)程“同步”機(jī)制,即各位線(xiàn)程之間要有個(gè)先來(lái)后到,不能一窩蜂擠上去搶作一團(tuán)。
同步這個(gè)詞是從英文synchronize(使同時(shí)發(fā)生)翻譯過(guò)來(lái)的。我也不明白為什么要用這個(gè)很容易引起誤解的詞。既然大家都這么用,咱們也就只好這么將就。
線(xiàn)程同步的真實(shí)意思和字面意思恰好相反。線(xiàn)程同步的真實(shí)意思,其實(shí)是“排隊(duì)”:幾個(gè)線(xiàn)程之間要排隊(duì),一個(gè)一個(gè)對(duì)共享資源進(jìn)行操作,而不是同時(shí)進(jìn)行操作。

因此,關(guān)于線(xiàn)程同步,需要牢牢記住的第一點(diǎn)是:線(xiàn)程同步就是線(xiàn)程排隊(duì)。同步就是排隊(duì)。線(xiàn)程同步的目的就是避免線(xiàn)程“同步”執(zhí)行。這可真是個(gè)無(wú)聊的繞口令。
關(guān)于線(xiàn)程同步,需要牢牢記住的第二點(diǎn)是 “共享”這兩個(gè)字。只有共享資源的讀寫(xiě)訪(fǎng)問(wèn)才需要同步。如果不是共享資源,那么就根本沒(méi)有同步的必要。
關(guān)于線(xiàn)程同步,需要牢牢記住的第三點(diǎn)是,只有“變量”才需要同步訪(fǎng)問(wèn)。如果共享的資源是固定不變的,那么就相當(dāng)于“常量”,線(xiàn)程同時(shí)讀取常量也不需要同步。至少一個(gè)線(xiàn)程修改共享資源,這樣的情況下,線(xiàn)程之間就需要同步。
關(guān)于線(xiàn)程同步,需要牢牢記住的第四點(diǎn)是:多個(gè)線(xiàn)程訪(fǎng)問(wèn)共享資源的代碼有可能是同一份代碼,也有可能是不同的代碼;無(wú)論是否執(zhí)行同一份代碼,只要這些線(xiàn)程的代碼訪(fǎng)問(wèn)同一份可變的共享資源,這些線(xiàn)程之間就需要同步。

為了加深理解,下面舉幾個(gè)例子。
有兩個(gè)采購(gòu)員,他們的工作內(nèi)容是相同的,都是遵循如下的步驟:
(1)到市場(chǎng)上去,尋找并購(gòu)買(mǎi)有潛力的樣品。
(2)回到公司,寫(xiě)報(bào)告。
這兩個(gè)人的工作內(nèi)容雖然一樣,他們都需要購(gòu)買(mǎi)樣品,他們可能買(mǎi)到同樣種類(lèi)的樣品,但是他們絕對(duì)不會(huì)購(gòu)買(mǎi)到同一件樣品,他們之間沒(méi)有任何共享資源。所以,他們可以各自進(jìn)行自己的工作,互不干擾。
這兩個(gè)采購(gòu)員就相當(dāng)于兩個(gè)線(xiàn)程;兩個(gè)采購(gòu)員遵循相同的工作步驟,相當(dāng)于這兩個(gè)線(xiàn)程執(zhí)行同一段代碼。

下面給這兩個(gè)采購(gòu)員增加一個(gè)工作步驟。采購(gòu)員需要根據(jù)公司的“布告欄”上面公布的信息,安排自己的工作計(jì)劃。
這兩個(gè)采購(gòu)員有可能同時(shí)走到布告欄的前面,同時(shí)觀看布告欄上的信息。這一點(diǎn)問(wèn)題都沒(méi)有。因?yàn)椴几鏅谑侵蛔x的,這兩個(gè)采購(gòu)員誰(shuí)都不會(huì)去修改布告欄上寫(xiě)的信息。

下面增加一個(gè)角色。一個(gè)辦公室行政人員這個(gè)時(shí)候,也走到了布告欄前面,準(zhǔn)備修改布告欄上的信息。
如果行政人員先到達(dá)布告欄,并且正在修改布告欄的內(nèi)容。兩個(gè)采購(gòu)員這個(gè)時(shí)候,恰好也到了。這兩個(gè)采購(gòu)員就必須等待行政人員完成修改之后,才能觀看修改后的信息。
如果行政人員到達(dá)的時(shí)候,兩個(gè)采購(gòu)員已經(jīng)在觀看布告欄了。那么行政人員需要等待兩個(gè)采購(gòu)員把當(dāng)前信息記錄下來(lái)之后,才能夠?qū)懮闲碌男畔ⅰ?
上述這兩種情況,行政人員和采購(gòu)員對(duì)布告欄的訪(fǎng)問(wèn)就需要進(jìn)行同步。因?yàn)槠渲幸粋€(gè)線(xiàn)程(行政人員)修改了共享資源(布告欄)。而且我們可以看到,行 政人員的工作流程和采購(gòu)員的工作流程(執(zhí)行代碼)完全不同,但是由于他們?cè)L問(wèn)了同一份可變共享資源(布告欄),所以他們之間需要同步。

同步鎖

前面講了為什么要線(xiàn)程同步,下面我們就來(lái)看如何才能線(xiàn)程同步。
線(xiàn)程同步的基本實(shí)現(xiàn)思路還是比較容易理解的。我們可以給共享資源加一把鎖,這把鎖只有一把鑰匙。哪個(gè)線(xiàn)程獲取了這把鑰匙,才有權(quán)利訪(fǎng)問(wèn)該共享資源。
生活中,我們也可能會(huì)遇到這樣的例子。一些超市的外面提供了一些自動(dòng)儲(chǔ)物箱。每個(gè)儲(chǔ)物箱都有一把鎖,一把鑰匙。人們可以使用那些帶有鑰匙的儲(chǔ)物 箱,把東西放到儲(chǔ)物箱里面,把儲(chǔ)物箱鎖上,然后把鑰匙拿走。這樣,該儲(chǔ)物箱就被鎖住了,其他人不能再訪(fǎng)問(wèn)這個(gè)儲(chǔ)物箱。(當(dāng)然,真實(shí)的儲(chǔ)物箱鑰匙是可以被人 拿走復(fù)制的,所以不要把貴重物品放在超市的儲(chǔ)物箱里面。于是很多超市都采用了電子密碼鎖。)
線(xiàn)程同步鎖這個(gè)模型看起來(lái)很直觀。但是,還有一個(gè)嚴(yán)峻的問(wèn)題沒(méi)有解決,這個(gè)同步鎖應(yīng)該加在哪里?
當(dāng)然是加在共享資源上了。反應(yīng)快的讀者一定會(huì)搶先回答。
沒(méi)錯(cuò),如果可能,我們當(dāng)然盡量把同步鎖加在共享資源上。一些比較完善的共享資源,比如,文件系統(tǒng),數(shù)據(jù)庫(kù)系統(tǒng)等,自身都提供了比較完善的同步鎖機(jī)制。我們不用另外給這些資源加鎖,這些資源自己就有鎖。
但是,大部分情況下,我們?cè)诖a中訪(fǎng)問(wèn)的共享資源都是比較簡(jiǎn)單的共享對(duì)象。這些對(duì)象里面沒(méi)有地方讓我們加鎖。
讀者可能會(huì)提出建議:為什么不在每一個(gè)對(duì)象內(nèi)部都增加一個(gè)新的區(qū)域,專(zhuān)門(mén)用來(lái)加鎖呢?這種設(shè)計(jì)理論上當(dāng)然也是可行的。問(wèn)題在于,線(xiàn)程同步的情況并不是很普遍。如果因?yàn)檫@小概率事件,在所有對(duì)象內(nèi)部都開(kāi)辟一塊鎖空間,將會(huì)帶來(lái)極大的空間浪費(fèi)。得不償失。
于是,現(xiàn)代的編程語(yǔ)言的設(shè)計(jì)思路都是把同步鎖加在代碼段上。確切的說(shuō),是把同步鎖加在“訪(fǎng)問(wèn)共享資源的代碼段”上。這一點(diǎn)一定要記住,同步鎖是加在代碼段上的。
同步鎖加在代碼段上,就很好地解決了上述的空間浪費(fèi)問(wèn)題。但是卻增加了模型的復(fù)雜度,也增加了我們的理解難度。
現(xiàn)在我們就來(lái)仔細(xì)分析“同步鎖加在代碼段上”的線(xiàn)程同步模型。
首先,我們已經(jīng)解決了同步鎖加在哪里的問(wèn)題。我們已經(jīng)確定,同步鎖不是加在共享資源上,而是加在訪(fǎng)問(wèn)共享資源的代碼段上。
其次,我們要解決的問(wèn)題是,我們應(yīng)該在代碼段上加什么樣的鎖。這個(gè)問(wèn)題是重點(diǎn)中的重點(diǎn)。這是我們尤其要注意的問(wèn)題:訪(fǎng)問(wèn)同一份共享資源的不同代碼段,應(yīng)該加上同一個(gè)同步鎖;如果加的是不同的同步鎖,那么根本就起不到同步的作用,沒(méi)有任何意義。
這就是說(shuō),同步鎖本身也一定是多個(gè)線(xiàn)程之間的共享對(duì)象。

Java語(yǔ)言的synchronized關(guān)鍵字

為了加深理解,舉幾個(gè)代碼段同步的例子。
不同語(yǔ)言的同步鎖模型都是一樣的。只是表達(dá)方式有些不同。這里我們以當(dāng)前最流行的Java語(yǔ)言為例。Java語(yǔ)言里面用synchronized關(guān)鍵字給代碼段加鎖。整個(gè)語(yǔ)法形式表現(xiàn)為
synchronized(同步鎖) {
  // 訪(fǎng)問(wèn)共享資源,需要同步的代碼段
}

這里尤其要注意的就是,同步鎖本身一定要是共享的對(duì)象。

… f1() {

Object lock1 = new Object(); // 產(chǎn)生一個(gè)同步鎖

synchronized(lock1){
  // 代碼段 A
// 訪(fǎng)問(wèn)共享資源 resource1
// 需要同步
}
}

上面這段代碼沒(méi)有任何意義。因?yàn)槟莻€(gè)同步鎖是在函數(shù)體內(nèi)部產(chǎn)生的。每個(gè)線(xiàn)程調(diào)用這段代碼的時(shí)候,都會(huì)產(chǎn)生一個(gè)新的同步鎖。那么多個(gè)線(xiàn)程之間,使用的是不同的同步鎖。根本達(dá)不到同步的目的。
同步代碼一定要寫(xiě)成如下的形式,才有意義。

public static final Object lock1 = new Object();

… f1() {

synchronized(lock1){ // lock1 是公用同步鎖
  // 代碼段 A
// 訪(fǎng)問(wèn)共享資源 resource1
// 需要同步
}

你不一定要把同步鎖聲明為static或者public,但是你一定要保證相關(guān)的同步代碼之間,一定要使用同一個(gè)同步鎖。
講到這里,你一定會(huì)好奇,這個(gè)同步鎖到底是個(gè)什么東西。為什么隨便聲明一個(gè)Object對(duì)象,就可以作為同步鎖?
在Java里面,同步鎖的概念就是這樣的。任何一個(gè)Object Reference都可以作為同步鎖。我們可以把Object Reference理解為對(duì)象在內(nèi)存分配系統(tǒng)中的內(nèi)存地址。因此,要保證同步代碼段之間使用的是同一個(gè)同步鎖,我們就要保證這些同步代碼段的 synchronized關(guān)鍵字使用的是同一個(gè)Object Reference,同一個(gè)內(nèi)存地址。這也是為什么我在前面的代碼中聲明lock1的時(shí)候,使用了final關(guān)鍵字,這就是為了保證lock1的 Object Reference在整個(gè)系統(tǒng)運(yùn)行過(guò)程中都保持不變。
一些求知欲強(qiáng)的讀者可能想要繼續(xù)深入了解synchronzied(同步鎖)的實(shí)際運(yùn)行機(jī)制。Java虛擬機(jī)規(guī)范中(你可以在google用 “JVM Spec”等關(guān)鍵字進(jìn)行搜索),有對(duì)synchronized關(guān)鍵字的詳細(xì)解釋。synchronized會(huì)編譯成 monitor enter, … monitor exit之類(lèi)的指令對(duì)。Monitor就是實(shí)際上的同步鎖。每一個(gè)Object Reference在概念上都對(duì)應(yīng)一個(gè)monitor。
這些實(shí)現(xiàn)細(xì)節(jié)問(wèn)題,并不是理解同步鎖模型的關(guān)鍵。我們繼續(xù)看幾個(gè)例子,加深對(duì)同步鎖模型的理解。

public static final Object lock1 = new Object();

… f1() {

synchronized(lock1){ // lock1 是公用同步鎖
  // 代碼段 A
// 訪(fǎng)問(wèn)共享資源 resource1
// 需要同步
}
}

… f2() {

synchronized(lock1){ // lock1 是公用同步鎖
  // 代碼段 B
// 訪(fǎng)問(wèn)共享資源 resource1
// 需要同步
}
}

上述的代碼中,代碼段A和代碼段B就是同步的。因?yàn)樗鼈兪褂玫氖峭粋€(gè)同步鎖lock1。
如果有10個(gè)線(xiàn)程同時(shí)執(zhí)行代碼段A,同時(shí)還有20個(gè)線(xiàn)程同時(shí)執(zhí)行代碼段B,那么這30個(gè)線(xiàn)程之間都是要進(jìn)行同步的。
這30個(gè)線(xiàn)程都要競(jìng)爭(zhēng)一個(gè)同步鎖lock1。同一時(shí)刻,只有一個(gè)線(xiàn)程能夠獲得lock1的所有權(quán),只有一個(gè)線(xiàn)程可以執(zhí)行代碼段A或者代碼段B。其他競(jìng)爭(zhēng)失敗的線(xiàn)程只能暫停運(yùn)行,進(jìn)入到該同步鎖的就緒(Ready)隊(duì)列。
每一個(gè)同步鎖下面都掛了幾個(gè)線(xiàn)程隊(duì)列,包括就緒(Ready)隊(duì)列,待召(Waiting)隊(duì)列等。比如,lock1對(duì)應(yīng)的就緒隊(duì)列就可以叫做lock1 - ready queue。每個(gè)隊(duì)列里面都可能有多個(gè)暫停運(yùn)行的線(xiàn)程。
注意,競(jìng)爭(zhēng)同步鎖失敗的線(xiàn)程進(jìn)入的是該同步鎖的就緒(Ready)隊(duì)列,而不是后面要講述的待召隊(duì)列(Waiting Queue,也可以翻譯為等待隊(duì)列)。就緒隊(duì)列里面的線(xiàn)程總是時(shí)刻準(zhǔn)備著競(jìng)爭(zhēng)同步鎖,時(shí)刻準(zhǔn)備著運(yùn)行。而待召隊(duì)列里面的線(xiàn)程則只能一直等待,直到等到某個(gè) 信號(hào)的通知之后,才能夠轉(zhuǎn)移到就緒隊(duì)列中,準(zhǔn)備運(yùn)行。
成功獲取同步鎖的線(xiàn)程,執(zhí)行完同步代碼段之后,會(huì)釋放同步鎖。該同步鎖的就緒隊(duì)列中的其他線(xiàn)程就繼續(xù)下一輪同步鎖的競(jìng)爭(zhēng)。成功者就可以繼續(xù)運(yùn)行,失敗者還是要乖乖地待在就緒隊(duì)列中。
因此,線(xiàn)程同步是非常耗費(fèi)資源的一種操作。我們要盡量控制線(xiàn)程同步的代碼段范圍。同步的代碼段范圍越小越好。我們用一個(gè)名詞“同步粒度”來(lái)表示同步代碼段的范圍。
同步粒度
在Java語(yǔ)言里面,我們可以直接把synchronized關(guān)鍵字直接加在函數(shù)的定義上。
比如。
… synchronized … f1() {
  // f1 代碼段
}

這段代碼就等價(jià)于
… f1() {
  synchronized(this){ // 同步鎖就是對(duì)象本身
    // f1 代碼段
  }
}

同樣的原則適用于靜態(tài)(static)函數(shù)
比如。
… static synchronized … f1() {
  // f1 代碼段
}

這段代碼就等價(jià)于
…static … f1() {
  synchronized(Class.forName(…)){ // 同步鎖是類(lèi)定義本身
    // f1 代碼段
  }
}

但是,我們要盡量避免這種直接把synchronized加在函數(shù)定義上的偷懶做法。因?yàn)槲覀円刂仆搅6?。同步的代碼段越小越好。synchronized控制的范圍越小越好。
我們不僅要在縮小同步代碼段的長(zhǎng)度上下功夫,我們同時(shí)還要注意細(xì)分同步鎖。
比如,下面的代碼

public static final Object lock1 = new Object();

… f1() {

synchronized(lock1){ // lock1 是公用同步鎖
  // 代碼段 A
// 訪(fǎng)問(wèn)共享資源 resource1
// 需要同步
}
}

… f2() {

synchronized(lock1){ // lock1 是公用同步鎖
  // 代碼段 B
// 訪(fǎng)問(wèn)共享資源 resource1
// 需要同步
}
}

… f3() {

synchronized(lock1){ // lock1 是公用同步鎖
  // 代碼段 C
// 訪(fǎng)問(wèn)共享資源 resource2
// 需要同步
}
}

… f4() {

synchronized(lock1){ // lock1 是公用同步鎖
  // 代碼段 D
// 訪(fǎng)問(wèn)共享資源 resource2
// 需要同步
}
}

上述的4段同步代碼,使用同一個(gè)同步鎖lock1。所有調(diào)用4段代碼中任何一段代碼的線(xiàn)程,都需要競(jìng)爭(zhēng)同一個(gè)同步鎖lock1。
我們仔細(xì)分析一下,發(fā)現(xiàn)這是沒(méi)有必要的。
因?yàn)閒1()的代碼段A和f2()的代碼段B訪(fǎng)問(wèn)的共享資源是resource1,f3()的代碼段C和f4()的代碼段D訪(fǎng)問(wèn)的共享資源是 resource2,它們沒(méi)有必要都競(jìng)爭(zhēng)同一個(gè)同步鎖lock1。我們可以增加一個(gè)同步鎖lock2。f3()和f4()的代碼可以修改為:
public static final Object lock2 = new Object();

… f3() {

synchronized(lock2){ // lock2 是公用同步鎖
  // 代碼段 C
// 訪(fǎng)問(wèn)共享資源 resource2
// 需要同步
}
}

… f4() {

synchronized(lock2){ // lock2 是公用同步鎖
  // 代碼段 D
// 訪(fǎng)問(wèn)共享資源 resource2
// 需要同步
}
}

這樣,f1()和f2()就會(huì)競(jìng)爭(zhēng)lock1,而f3()和f4()就會(huì)競(jìng)爭(zhēng)lock2。這樣,分開(kāi)來(lái)分別競(jìng)爭(zhēng)兩個(gè)鎖,就可以大大較少同步鎖競(jìng)爭(zhēng)的概率,從而減少系統(tǒng)的開(kāi)銷(xiāo)。

信號(hào)量

同步鎖模型只是最簡(jiǎn)單的同步模型。同一時(shí)刻,只有一個(gè)線(xiàn)程能夠運(yùn)行同步代碼。
有的時(shí)候,我們希望處理更加復(fù)雜的同步模型,比如生產(chǎn)者/消費(fèi)者模型、讀寫(xiě)同步模型等。這種情況下,同步鎖模型就不夠用了。我們需要一個(gè)新的模型。這就是我們要講述的信號(hào)量模型。
信號(hào)量模型的工作方式如下:線(xiàn)程在運(yùn)行的過(guò)程中,可以主動(dòng)停下來(lái),等待某個(gè)信號(hào)量的通知;這時(shí)候,該線(xiàn)程就進(jìn)入到該信號(hào)量的待召(Waiting)隊(duì)列當(dāng)中;等到通知之后,再繼續(xù)運(yùn)行。
很多語(yǔ)言里面,同步鎖都由專(zhuān)門(mén)的對(duì)象表示,對(duì)象名通常叫Monitor。
同樣,在很多語(yǔ)言中,信號(hào)量通常也有專(zhuān)門(mén)的對(duì)象名來(lái)表示,比如,Mutex,Semphore。
信號(hào)量模型要比同步鎖模型復(fù)雜許多。一些系統(tǒng)中,信號(hào)量甚至可以跨進(jìn)程進(jìn)行同步。另外一些信號(hào)量甚至還有計(jì)數(shù)功能,能夠控制同時(shí)運(yùn)行的線(xiàn)程數(shù)。
我們沒(méi)有必要考慮那么復(fù)雜的模型。所有那些復(fù)雜的模型,都是最基本的模型衍生出來(lái)的。只要掌握了最基本的信號(hào)量模型——“等待/通知”模型,復(fù)雜模型也就迎刃而解了。
我們還是以Java語(yǔ)言為例。Java語(yǔ)言里面的同步鎖和信號(hào)量概念都非常模糊,沒(méi)有專(zhuān)門(mén)的對(duì)象名詞來(lái)表示同步鎖和信號(hào)量,只有兩個(gè)同步鎖相關(guān)的關(guān)鍵字——volatile和synchronized。
這種模糊雖然導(dǎo)致概念不清,但同時(shí)也避免了Monitor、Mutex、Semphore等名詞帶來(lái)的種種誤解。我們不必執(zhí)著于名詞之爭(zhēng),可以專(zhuān)注于理解實(shí)際的運(yùn)行原理。
在Java語(yǔ)言里面,任何一個(gè)Object Reference都可以作為同步鎖。同樣的道理,任何一個(gè)Object Reference也可以作為信號(hào)量。
Object對(duì)象的wait()方法就是等待通知,Object對(duì)象的notify()方法就是發(fā)出通知。
具體調(diào)用方法為
(1)等待某個(gè)信號(hào)量的通知
public static final Object signal = new Object();

… f1() {
synchronized(singal) { // 首先我們要獲取這個(gè)信號(hào)量。這個(gè)信號(hào)量同時(shí)也是一個(gè)同步鎖

    // 只有成功獲取了signal這個(gè)信號(hào)量兼同步鎖之后,我們才可能進(jìn)入這段代碼
    signal.wait(); // 這里要放棄信號(hào)量。本線(xiàn)程要進(jìn)入signal信號(hào)量的待召(Waiting)隊(duì)列

// 可憐。辛辛苦苦爭(zhēng)取到手的信號(hào)量,就這么被放棄了

    // 等到通知之后,從待召(Waiting)隊(duì)列轉(zhuǎn)到就緒(Ready)隊(duì)列里面
// 轉(zhuǎn)到了就緒隊(duì)列中,離CPU核心近了一步,就有機(jī)會(huì)繼續(xù)執(zhí)行下面的代碼了。
// 仍然需要把signal同步鎖競(jìng)爭(zhēng)到手,才能夠真正繼續(xù)執(zhí)行下面的代碼。命苦啊。
    …
}
}

需要注意的是,上述代碼中的signal.wait()的意思。signal.wait()很容易導(dǎo)致誤解。signal.wait()的意思并 不是說(shuō),signal開(kāi)始wait,而是說(shuō),運(yùn)行這段代碼的當(dāng)前線(xiàn)程開(kāi)始wait這個(gè)signal對(duì)象,即進(jìn)入signal對(duì)象的待召(Waiting) 隊(duì)列。

(2)發(fā)出某個(gè)信號(hào)量的通知
… f2() {
synchronized(singal) { // 首先,我們同樣要獲取這個(gè)信號(hào)量。同時(shí)也是一個(gè)同步鎖。

    // 只有成功獲取了signal這個(gè)信號(hào)量兼同步鎖之后,我們才可能進(jìn)入這段代碼
signal.notify(); // 這里,我們通知signal的待召隊(duì)列中的某個(gè)線(xiàn)程。

// 如果某個(gè)線(xiàn)程等到了這個(gè)通知,那個(gè)線(xiàn)程就會(huì)轉(zhuǎn)到就緒隊(duì)列中
// 但是本線(xiàn)程仍然繼續(xù)擁有signal這個(gè)同步鎖,本線(xiàn)程仍然繼續(xù)執(zhí)行
// 嘿嘿,雖然本線(xiàn)程好心通知其他線(xiàn)程,
// 但是,本線(xiàn)程可沒(méi)有那么高風(fēng)亮節(jié),放棄到手的同步鎖
// 本線(xiàn)程繼續(xù)執(zhí)行下面的代碼
    …
}
}

需要注意的是,signal.notify()的意思。signal.notify()并不是通知signal這個(gè)對(duì)象本身。而是通知正在等待signal信號(hào)量的其他線(xiàn)程。

以上就是Object的wait()和notify()的基本用法。
實(shí)際上,wait()還可以定義等待時(shí)間,當(dāng)線(xiàn)程在某信號(hào)量的待召隊(duì)列中,等到足夠長(zhǎng)的時(shí)間,就會(huì)等無(wú)可等,無(wú)需再等,自己就從待召隊(duì)列轉(zhuǎn)移到就緒隊(duì)列中了。
另外,還有一個(gè)notifyAll()方法,表示通知待召隊(duì)列里面的所有線(xiàn)程。
這些細(xì)節(jié)問(wèn)題,并不對(duì)大局產(chǎn)生影響。

綠色線(xiàn)程

綠色線(xiàn)程(Green Thread)是一個(gè)相對(duì)于操作系統(tǒng)線(xiàn)程(Native Thread)的概念。
操作系統(tǒng)線(xiàn)程(Native Thread)的意思就是,程序里面的線(xiàn)程會(huì)真正映射到操作系統(tǒng)的線(xiàn)程,線(xiàn)程的運(yùn)行和調(diào)度都是由操作系統(tǒng)控制的
綠色線(xiàn)程(Green Thread)的意思是,程序里面的線(xiàn)程不會(huì)真正映射到操作系統(tǒng)的線(xiàn)程,而是由語(yǔ)言運(yùn)行平臺(tái)自身來(lái)調(diào)度。
當(dāng)前版本的Python語(yǔ)言的線(xiàn)程就可以映射到操作系統(tǒng)線(xiàn)程。當(dāng)前版本的Ruby語(yǔ)言的線(xiàn)程就屬于綠色線(xiàn)程,無(wú)法映射到操作系統(tǒng)的線(xiàn)程,因此Ruby語(yǔ)言的線(xiàn)程的運(yùn)行速度比較慢。
難道說(shuō),綠色線(xiàn)程要比操作系統(tǒng)線(xiàn)程要慢嗎?當(dāng)然不是這樣。事實(shí)上,情況可能正好相反。Ruby是一個(gè)特殊的例子。線(xiàn)程調(diào)度器并不是很成熟。
目前,線(xiàn)程的流行實(shí)現(xiàn)模型就是綠色線(xiàn)程。比如,stackless Python,就引入了更加輕量的綠色線(xiàn)程概念。在線(xiàn)程并發(fā)編程方面,無(wú)論是運(yùn)行速度還是并發(fā)負(fù)載上,都優(yōu)于Python。
另一個(gè)更著名的例子就是ErLang(愛(ài)立信公司開(kāi)發(fā)的一種開(kāi)源語(yǔ)言)。
ErLang的綠色線(xiàn)程概念非常徹底。ErLang的線(xiàn)程不叫Thread,而是叫做Process。這很容易和進(jìn)程混淆起來(lái)。這里要注意區(qū)分一下。
ErLang Process之間根本就不需要同步。因?yàn)镋rLang語(yǔ)言的所有變量都是final的,不允許變量的值發(fā)生任何變化。因此根本就不需要同步。
final變量的另一個(gè)好處就是,對(duì)象之間不可能出現(xiàn)交叉引用,不可能構(gòu)成一種環(huán)狀的關(guān)聯(lián),對(duì)象之間的關(guān)聯(lián)都是單向的,樹(shù)狀的。因此,內(nèi)存垃圾回 收的算法效率也非常高。這就讓ErLang能夠達(dá)到Soft Real Time(軟實(shí)時(shí))的效果。這對(duì)于一門(mén)支持內(nèi)存垃圾回收的語(yǔ)言來(lái)說(shuō),可不是一件容易的事情。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多