iOS中關(guān)于線程和隊列蜂嗽,有一些概念:
隊列
、串行隊列
响禽、并發(fā)隊列
徒爹、主線程
荚醒、主隊列
芋类、任務(wù)
隆嗅、同步
、異步
侯繁。這些概念的意義和聯(lián)系又是什么呢胖喳?
本質(zhì)上
- 隊列:隊列就是一個裝任務(wù)的容器,存儲著需要執(zhí)行的各個任務(wù)贮竟。FIFO(先進(jìn)先出原則)
- 線程:線程就是具體的執(zhí)行任務(wù)的人丽焊,是干活的。隊列中的任務(wù)的執(zhí)行要在線程中執(zhí)行咕别。一直在跑代碼流技健。
- 串行隊列:執(zhí)行里面的B任務(wù)需要等待他前面的A任務(wù)執(zhí)行完畢才能執(zhí)行。存放任務(wù)符合隊列的本質(zhì):FIFO(先進(jìn)先出)惰拱。
- 并發(fā)隊列:執(zhí)行隊列里面的B任務(wù)雌贱,不需要等待他前面的A任務(wù)執(zhí)行完畢才能執(zhí)行。存放任務(wù)符合隊列的本質(zhì):FIFO偿短。
- 主隊列:系統(tǒng)自動生成的欣孤,用于存放任務(wù)的隊列,只有唯一的一個昔逗,他是串行隊列降传。任務(wù)默認(rèn)都存放在主隊列。
- 主線程:與主隊列相關(guān)聯(lián)的系統(tǒng)生成的用于干活的線程勾怒。任務(wù)默認(rèn)都是在主線程中執(zhí)行婆排。主線程會去調(diào)度系統(tǒng)資源,確定是否需要開辟新的線程來干活笔链。
- 同步:針對當(dāng)前線程的任務(wù)的代碼流段只,當(dāng)前線程如果在執(zhí)行任務(wù)的過程中需要同步執(zhí)行一個新的任務(wù)的時候,新任務(wù)會被立即執(zhí)行卡乾,之前沒有執(zhí)行完的任務(wù)會停止執(zhí)行翼悴,進(jìn)入等待狀態(tài)。形成一個阻塞幔妨。
- 異步: 針對當(dāng)前線程的任務(wù)的代碼流鹦赎,當(dāng)前線程如果在執(zhí)行任務(wù)的過程中需要異步執(zhí)行一個新的任務(wù)的時候,新任務(wù)會被立即執(zhí)行误堡,但是新任務(wù)并不會阻塞當(dāng)前線程古话。
一、串行隊列锁施、同步執(zhí)行
向串行隊列提交同步的任務(wù)的時候的執(zhí)行情況:
let s = DispatchQueue(label: "s")
for i in 0..<5 {
print("+ 添加任務(wù):\(i)")
s.sync {
print("- 執(zhí)行:\(i)")
print("current: \(i), currentThread: \(Thread.current), isMainThread: \(Thread.current.isMainThread)")
print("= 執(zhí)行完畢:\(i)")
}
}
通過結(jié)果我們知道:
- 任務(wù)的情況:(加上了定語:在串行隊列陪踩、同步的)任務(wù)杖们。
- 主線程的行為:不開辟新的線程在當(dāng)前的主線程中執(zhí)行。
- 串行的效果:所有任務(wù)的執(zhí)行都是等待上一個任務(wù)執(zhí)行完畢之后再執(zhí)行肩狂。
- 同步的效果:任務(wù)的執(zhí)行阻塞了當(dāng)前線程(主線程)的代碼流摘完,阻斷了For循環(huán)的進(jìn)行,等任務(wù)執(zhí)行完了才會繼續(xù)For循環(huán)傻谁。
二孝治、串行隊列、異步執(zhí)行
向串行隊列提交異步任務(wù)的執(zhí)行情況:
let s = DispatchQueue(label: "s")
for i in 0..<5 {
print("+ 添加任務(wù):\(i)")
s.async {
print("- 執(zhí)行:\(i)")
print("current: \(i), currentThread: \(Thread.current), isMainThread: \(Thread.current.isMainThread)")
print("= 執(zhí)行完畢:\(i)")
}
}
通過結(jié)果我們知道:
- 任務(wù)的情況:(加上了定語:在串行隊列审磁、異步的)任務(wù)谈飒。
- 主線程的行為:開辟新的線程,在 同一個 新的線程中進(jìn)行任務(wù)态蒂。
- 串行的效果:所有任務(wù)的執(zhí)行都是等待上一個任務(wù)執(zhí)行完畢之后再執(zhí)行杭措。系統(tǒng)非常聰明因為是串行,所以只需要開一個線程就是依次的執(zhí)行了钾恢。
- 異步的效果:任務(wù)的執(zhí)行沒有阻塞當(dāng)前線程(主線程)的代碼流手素,沒有阻斷For循環(huán)的進(jìn)行,F(xiàn)or循環(huán)始終在執(zhí)行赘那。
三刑桑、并發(fā)隊列、同步執(zhí)行
向并發(fā)隊列中提交同步任務(wù):
let c = DispatchQueue(label: "c", attributes: .concurrent)
for i in 0..<5 {
print("+ 添加任務(wù):\(i)")
c.sync {
print("- 執(zhí)行:\(i)")
print("current: \(i), currentThread: \(Thread.current), isMainThread: \(Thread.current.isMainThread)")
print("= 執(zhí)行完畢:\(i)")
}
}
我們可以看到募舟,效果和上面的“一”是一樣的祠斧。
通過結(jié)果我們知道:
- 任務(wù)的情況:(加上了定語:在并發(fā)隊列、同步的)任務(wù)拱礁。
- 主線程的行為:不開辟新的線程在當(dāng)前的主線程中執(zhí)行琢锋。
- 并發(fā)的效果:由于沒有開辟新的線程,同步執(zhí)行又阻塞了主線程呢灶,所以吴超,效果還是執(zhí)行完一個任務(wù),然后才開始執(zhí)行下一個任務(wù)鸯乃。
- 同步的效果:任務(wù)的執(zhí)行阻塞了當(dāng)前線程(主線程)的代碼流鲸阻,阻斷了For循環(huán)的進(jìn)行,等任務(wù)執(zhí)行完了才會繼續(xù)For循環(huán)缨睡。
四鸟悴、并發(fā)隊列,異步執(zhí)行
像并發(fā)隊列中提交異步任務(wù):
let c = DispatchQueue(label: "c", attributes: .concurrent)
for i in 0..<5 {
print("+ 添加任務(wù):\(i)")
c.async {
print("- 執(zhí)行:\(i)")
print("current: \(i), currentThread: \(Thread.current), isMainThread: \(Thread.current.isMainThread)")
print("= 執(zhí)行完畢:\(i)")
}
}
通過結(jié)果我們知道:
- 任務(wù)的情況:(加上了定語:在并發(fā)隊列奖年、異步的)任務(wù)细诸。
- 主線程的行為:開辟新的線程,在 不一定相同 的新的線程中進(jìn)行任務(wù)陋守。由于是并發(fā)且異步震贵,要想實現(xiàn)各個任務(wù)的代碼流的互不干擾不阻塞也不依賴利赋,就需要多開辟一些線程才可以。
- 并發(fā)的效果:任務(wù)不必等待上一個任務(wù)完成就可以開始執(zhí)行猩系。
- 異步的效果:任務(wù)的執(zhí)行沒有阻塞當(dāng)前線程(主線程)的代碼流媚送,沒有阻斷For循環(huán)的進(jìn)行,F(xiàn)or循環(huán)始終在執(zhí)行蝙眶。
死鎖
通過上面的各種情況季希,我們就可以引申出死鎖的產(chǎn)生原因以及狀態(tài)了褪那。那就是:
1幽纷、當(dāng)我們向一個 串行隊列 中放入一個 同步執(zhí)行任務(wù)A
2、但是博敬,這個 同步執(zhí)行任務(wù)A 又包括了一個向隊列中放置的 同步執(zhí)行任務(wù)a
3友浸、兩個任務(wù)是嵌套關(guān)系,A執(zhí)行的時候會阻塞當(dāng)前線程已有的任務(wù)偏窝,當(dāng)前線程立即執(zhí)行A任務(wù)
4收恢、但是A任務(wù)里面又包涵一個提交到隊列的同步任務(wù)a
5、這個任務(wù)a是在A之后提交的祭往,由于在串行隊列中伦意,所以a需要等待A完成之后才能執(zhí)行
6、但是a是個同步任務(wù)硼补,提交之后要立即阻塞并且執(zhí)行驮肉。
7、此時A的執(zhí)行被a所阻塞已骇,但是a的執(zhí)行要等A執(zhí)行完畢之后才能執(zhí)行
8离钝、所以最終,A要等a執(zhí)行完畢才能繼續(xù)褪储,a要等A執(zhí)行完了才能開始執(zhí)行
9卵渴、這倆任務(wù)互相等待,導(dǎo)致當(dāng)前線程永遠(yuǎn)停滯不前鲤竹,就發(fā)生了死鎖浪读。
說起來都十分拗口,但是死鎖最終產(chǎn)生的原因就是兩個任務(wù)因為阻塞相互等待的情況辛藻。這也是在使用多線程開發(fā)過程中需要十分注意的地方碘橘。