1、信號量(Semaphore)
定義:信號量就是一個資源計數(shù)器,就是一種可用來控制訪問資源數(shù)量的標(biāo)識。
通過添加信號量的處理,則可告訴系統(tǒng)按照我們指定的信號量數(shù)量來執(zhí)行多個線程。類似鎖機(jī)制。
更通俗的來理解信號量其實就像是一間可容納n個人的教室(初始信號量為n),上課鈴響了(程序進(jìn)程運(yùn)行),n個學(xué)生(即對應(yīng)n條線程)都跑進(jìn)了該教室坐滿了位置,好好聽課~此時座位坐滿,沒座位了(即信號量為0),其他小伙伴想進(jìn)這個教室聽課也進(jìn)不來了。中間有兩個學(xué)生突然覺得尿意襲來,就相約跑出去上廁所了。此時教室里就空出來兩個位置(信號量+2),其他小伙伴就可以趁這個機(jī)會進(jìn)來聽課~這時候教室又被坐滿了(信號量-2),剛剛?cè)瞿虻膬蓚€同學(xué)回來發(fā)現(xiàn)沒位置了,只能被擋在門外(阻塞)不得進(jìn)教室聽課學(xué)習(xí),大體流程就是這樣啦~
舉個??


輸出結(jié)果可知:可以觀察到當(dāng)注釋掉semaphore.wait()這一行,i的輸出結(jié)果不同。原因:由于我們是將block異步添加到一個并行隊列里面(子線程),所以程序執(zhí)行的時候會先執(zhí)行主線程的代碼,直接執(zhí)行到semaphore.wait()這一行,因為此時的semaphore的信號量為0,所以當(dāng)前線程會一直阻塞,直到block在子線程執(zhí)行到semaphore.signal()這一行,使得信號量+1,進(jìn)而程序可以繼續(xù)往下走。
再舉個??,為線程加鎖
同時可以控制最大并發(fā)數(shù)量,value的值決定最多幾個并發(fā)。
func semaphore2() {
let semaphore = DispatchSemaphore(value: 1)
for i in 0..<100 {
DispatchQueue.global().async {
semaphore.wait()
print("i =", i)
semaphore.signal()
}
}
}
當(dāng)子線程1執(zhí)行到semaphore.wait()這一行的時候,semaphore的信號量為1,所以此時-1變?yōu)?,并且子線程1繼續(xù)往下執(zhí)行;如果當(dāng)在子線程1的print這一行代碼還沒執(zhí)行完的時候,又有子線程2訪問進(jìn)來了,同樣執(zhí)行到semaphore.wait()時,由于此時信號量為0(注意:.wait()方法默認(rèn)時間是 OC 的DISPATCH_TIME_FOREVER),所以會一直阻塞子線程2(此時子線程2就處于等待狀態(tài)),直到子線程1執(zhí)行完print并執(zhí)行完semaphore.signal()使信號量+1等于1后,子線程2才可以不被阻塞繼續(xù)往下執(zhí)行。這樣就可以保證同時只有一個子線程執(zhí)行print這一行代碼。
加一把小鎖??
func synchronized(_ lock: AnyObject, _ closure: () -> Void) {
objc_sync_enter(lock)
closure()
objc_sync_exit(lock)
}
// 實現(xiàn)一個線程安全的setter
class Obj {
var _str = "123"
var str: String {
get { return _str }
set {
self.synchronized(self) {
_str = newValue
}
}
}
}
實際應(yīng)用小??
在開發(fā)中,我們有時候會需要等待某個網(wǎng)絡(luò)回調(diào)完成之后再繼續(xù)進(jìn)行下一操作,就可以這樣寫:

2、柵欄函數(shù)(barrier)
使用barrier函數(shù)可以做到異步執(zhí)行多個任務(wù)完成后,再執(zhí)行之后的任務(wù),它會阻塞當(dāng)前子線程。

3、GCD組的用法(Group)
使用group + notify的話,也會等待隊列的任務(wù)先執(zhí)行完畢,和柵欄函數(shù)的區(qū)別在于它不會阻塞當(dāng)前子線程。

wait + group組合

使用wait + group的話,會等待隊列的任務(wù)先執(zhí)行,且阻塞當(dāng)前子線程,如若出現(xiàn)超時,則會執(zhí)行往下繼續(xù)執(zhí)行,上面的任務(wù)依舊繼續(xù)執(zhí)行。此處的timeout可設(shè)置為distantFuture即無限等待(類似barrier函數(shù))。
進(jìn)階用法暫且就這么多啦,一定要多寫多嘗試多用,方可得心應(yīng)手。
部分資料來源于網(wǎng)絡(luò),若侵權(quán),請聯(lián)系刪除~
聯(lián)系方式:kim77895pl@gmail.com
Kim 寫于2020.8.18,希望文章能對你有所幫助。