聊聊高并發(fā)(三)鎖的一些基本概念

理解并發(fā)編程的一些基本概念很重要,給我們思考問題指明一個(gè)基本的方向。這篇說一說鎖的一些基本概念。

在通常情況下我們說的鎖都指的是“互斥”鎖,因?yàn)樵谶€存在一些特殊的鎖,比如“讀寫鎖”,不完全是互斥的。這篇文章說的鎖專指互斥鎖。

鎖是處理并發(fā)的一種同步手段。單線程程序和并發(fā)程序的最終目的都是要保證程序的正確性,但是最大的區(qū)別是:

單線程程序的正確性只關(guān)注程序的運(yùn)行結(jié)果和目標(biāo)是一致的
并發(fā)程序的正確性除了運(yùn)行結(jié)果正確外,還包含了活性的特性,所謂活性,指的就是程序無(wú)死鎖,無(wú)饑餓

所以考察一個(gè)鎖,也需要從三個(gè)方面考察:

  1. 互斥性

  2. 無(wú)死鎖

  3. 無(wú)饑餓

最簡(jiǎn)單的鎖只保證互斥性,而互斥性本質(zhì)上可以用一個(gè)布爾值表示,即一個(gè)二元狀態(tài)。

互斥是保證并發(fā)程序正確性的一種特性,和互斥相關(guān)的一個(gè)專用名詞就是臨界區(qū)

臨界區(qū)指的是“某個(gè)時(shí)刻僅能被一個(gè)線程執(zhí)行的代碼段”,也就是通常鎖的被鎖保護(hù)的代碼段。

一個(gè)互斥鎖的定義通常如下

interface Lock {
     public void lock();
     public void unlock();
}

線程必須用指定的方式使用鎖,lock動(dòng)作必須在try塊之前調(diào)用,如果lock在try里面執(zhí)行,可能會(huì)在取到鎖之前拋出異常,導(dǎo)致執(zhí)行了unlock動(dòng)作,從而發(fā)生錯(cuò)誤。

熟悉Java顯示鎖的同學(xué)肯定知道使用ReentryLock就是如下的用法。

mutex.lock();
try{
 ...臨界區(qū)
}finally{
    mutex.unlock()
}

互斥意味著串行,也意味著等待。 這引出了著名的Amdahl定律

Amdahl定律: 即完成一個(gè)工作能獲得的加速比,受限于這個(gè)工作中必須被串行的部分。(通常串行部分都是因?yàn)楸换コ怄i保護(hù)了)

加速比的定義是一個(gè)處理器完成一個(gè)工作的時(shí)間和采用n個(gè)處理器并發(fā)完成該工作的時(shí)間比。

Amdahl定律給出的加速比如下
 
S = 1 / ( 1 - p + p/n)
 
S為加速比
1為完成工作的時(shí)間
p指可以并行的部分
n指處理器個(gè)數(shù)

從Amdahl定律可以看出,串行的工作越多,獲得的加速比就越小。

Amdahl給我們編程實(shí)際啟示有:

  1. 盡量減小互斥鎖的粒度,鎖粒度越小表示串行的部分越少

  2. 能不用鎖,就不要用鎖。不用鎖表示串行的部分越少

接下來說說活性相關(guān)的概念。

死鎖意味者系統(tǒng)凍結(jié),最終相關(guān)的所有線程都永久地停滯等待。

饑餓則是總有一些線程能夠運(yùn)行,一小部分線程永久停滯等待

所以無(wú)饑餓意味著肯定無(wú)死鎖。但是無(wú)死鎖不意味著無(wú)饑餓。

《多處理器編程的藝術(shù)》一書中給出了幾種鎖的實(shí)現(xiàn),其中Peterson算法可以保證兩個(gè)線程使用鎖的時(shí)候鎖具備互斥,無(wú)死鎖,無(wú)饑餓特性。

class Peterson implements Lock {
     private boolean[] flag = new boolean[2];
     private int victim;
     public void lock(){
           int i = ThreadID.get();
           int j = 1 - i;
           flag[i]= true;  // 保證兩個(gè)線程先后運(yùn)行不死鎖,實(shí)現(xiàn)互斥 
           victim = i;  // 保證兩個(gè)線程同時(shí)運(yùn)行時(shí)不死鎖,實(shí)現(xiàn)互斥
           while(flag[j] && victim == i){}  // 互斥意味著等待
     }
 
     public void unlock(){
           int i = ThreadID.get();
           flag[i] = false;
    }
 
}

Bakery鎖支持n個(gè)線程的互斥協(xié)議。通過數(shù)學(xué)證明了:

n線程的無(wú)死鎖互斥算法需要n個(gè)不同的存儲(chǔ)單元(變量)來保存中間狀態(tài)。

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

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

  • 本文是我自己在秋招復(fù)習(xí)時(shí)的讀書筆記,整理的知識(shí)點(diǎn),也是為了防止忘記,尊重勞動(dòng)成果,轉(zhuǎn)載注明出處哦!如果你也喜歡,那...
    波波波先森閱讀 11,595評(píng)論 4 56
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時(shí)...
    歐辰_OSR閱讀 30,203評(píng)論 8 265
  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,893評(píng)論 0 11
  • 一.線程安全性 線程安全是建立在對(duì)于對(duì)象狀態(tài)訪問操作進(jìn)行管理,特別是對(duì)共享的與可變的狀態(tài)的訪問 解釋下上面的話: ...
    黃大大吃不胖閱讀 952評(píng)論 0 3
  • 點(diǎn)評(píng):“自古華山一條路!不吃豹子膽,唯有望峰嘆!”華山被喻為“奇險(xiǎn)天下第一山”,長(zhǎng)空棧道也是全球十大最恐怖的懸崖步...
    攜程攻略社區(qū)閱讀 284評(píng)論 0 0

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