NSConditionLock條件鎖在開發(fā)中幾乎很少用到,雖然知道他的作用但是之前并沒有碰到一個用它解決問題的場景。
描述如下一個場景:三個異步任務(wù)在并發(fā)隊列中,同時執(zhí)行一個耗時任務(wù)X,當(dāng)X執(zhí)行完畢之后會回調(diào)一次數(shù)據(jù),如何保證調(diào)用順序和回調(diào)順序一致?
eg:ABC三個異步任務(wù)依次書寫,并發(fā)異步下假如實際調(diào)用順序為BCA,希望回調(diào)順序也是BCA,但其實可能A執(zhí)行X時最先處理完,但不回調(diào),等待BC回調(diào)過后再進(jìn)行回調(diào),即調(diào)用順序為BCA,回調(diào)順序為BCA,且并發(fā)。
利用NSConditionLock可以比較方便實現(xiàn)這個效果,思路如下:通過一個容器記錄方法的調(diào)用順序,主動解鎖第一個調(diào)用,第一個調(diào)用一次解鎖剩下的調(diào)用。
前置一個問題,如果我先進(jìn)行條件解鎖,再進(jìn)行同條件加鎖,此處無效,像下面這樣
self.conditionLock.unlock(withCondition: 4)
self.conditionLock.lock(whenCondition: 4)
print("aaa")
正文:
變量部分:
var methodIndex : Array<Int> = Array() //標(biāo)記調(diào)用順序的容器
var methodIndexLock : NSLock = NSLock.init() //給容器讀寫加鎖的互斥鎖
var methodCurrnetLock : Int = 0 //當(dāng)前解鎖到的位置
lazy var conditionLock : NSConditionLock = {
return NSConditionLock.init(condition: 0)
}() //條件鎖
//并發(fā)調(diào)用三個異步任務(wù),為了比較直觀,我把第一個任務(wù)進(jìn)行延遲
func testConditionLock() {
DispatchQueue.global().asyncAfter(deadline: .now() + 0.5, execute: {
print("第一個任務(wù)開始了")
self.someMethod(1) {
print("第一個任務(wù)返回了")
}
})
DispatchQueue.global().async {
print("第二個任務(wù)開始了")
self.someMethod(2) {
print("第二個任務(wù)返回了")
}
}
DispatchQueue.global().async {
print("第三個任務(wù)開始了")
self.someMethod(3) {
print("第三個任務(wù)返回了")
}
}
//這里備注下:此處是希望解鎖第一個加鎖的,也就是像上面前置問題那樣,使第一把條件鎖無效
DispatchQueue.main.asyncAfter(deadline: .now()+1) {
self.conditionLock.unlock(withCondition: self.methodIndex[0])
}
}
//第一個參數(shù)只是一個標(biāo)識,不代表調(diào)用順序
func someMethod(_ actionIndex:Int,callback:()->Void) {
//對容器讀寫加鎖
self.methodIndexLock.lock()
self.methodIndex.append(actionIndex)
self.methodIndexLock.unlock()
let t = Double(arc4random() % 10)
Thread.sleep(forTimeInterval: t) //此處進(jìn)行休眠,模擬耗時操作
print(actionIndex,t)
self.conditionLock.lock(whenCondition: actionIndex)
callback()
self.methodCurrnetLock += 1
guard self.methodIndex.count > self.methodCurrnetLock else {
return
}
self.conditionLock.unlock(withCondition: self.methodIndex[self.methodCurrnetLock])
print(self.methodCurrnetLock,self.methodIndex)
}