多線程的理解

一.概念

串行(Serial)

多個(gè)任務(wù)放在串行隊(duì)列里執(zhí)行,只能按順序依次運(yùn)行,前一個(gè)運(yùn)行完成,下一個(gè)才能開始運(yùn)行;前一個(gè)沒運(yùn)行完,后一個(gè)只能排隊(duì)等著。以此類推,直到所有任務(wù)都運(yùn)行完成。

串行隊(duì)列.png

并發(fā)(Concurrency)

多個(gè)任務(wù)放在并行隊(duì)列里執(zhí)行,可以同時(shí)運(yùn)行.

并行隊(duì)列.png

串行和并行描述的是 任務(wù)和任務(wù)之間 的執(zhí)行方式;執(zhí)行順序不同,以及開啟線程數(shù)不同。

并發(fā)和并行

  • 并發(fā):(Concurrency)
    在操作系統(tǒng)中,是指一個(gè)時(shí)間段中有幾個(gè)程序都處于已啟動(dòng)運(yùn)行到運(yùn)行完畢之間,且這幾個(gè)程序都是在同一個(gè)處理機(jī)上運(yùn)行,但任一個(gè)時(shí)刻點(diǎn)上只有一個(gè)程序在處理機(jī)上運(yùn)行(不斷切換)。
  • 并行:(Parallelism)
    在操作系統(tǒng)中,一組程序按獨(dú)立異步的速度執(zhí)行,無論從微觀還是宏觀,程序都是一起執(zhí)行的。

單CPU系統(tǒng)中,系統(tǒng)調(diào)度在某一時(shí)刻只能讓一個(gè)線程運(yùn)行,雖然這種調(diào)試機(jī)制有多種形式(大多數(shù)是時(shí)間片輪巡為主),但無論如何,要通過不斷切換需要運(yùn)行的線程讓其運(yùn)行的方式就叫并發(fā)(concurrent)
而在多CPU系統(tǒng)中,可以讓兩個(gè)以上的線程同時(shí)運(yùn)行,這種可以同時(shí)讓兩個(gè)以上線程同時(shí)運(yùn)行的方式叫做并行(parallel)。

并發(fā)和并行微觀示意圖.png

同步sync:

  • 同步添加任務(wù)到指定的隊(duì)列中,在添加的任務(wù)執(zhí)行結(jié)束之前,會一直等待,直到隊(duì)列里面的任務(wù)完成之后再繼續(xù)執(zhí)行。
  • 只能在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力。

異步async:

  • 異步添加任務(wù)到指定的隊(duì)列中,它不會做任何等待,可以繼續(xù)執(zhí)行任務(wù)。
  • 可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力。
兩者的主要區(qū)別是:是否等待隊(duì)列的任務(wù)執(zhí)行結(jié)束,以及是否具備開啟新線程的能力。

注意:異步執(zhí)行(async)雖然具有開啟新線程的能力,但是并不一定開啟新線程。這跟任務(wù)所指定的隊(duì)列類型有關(guān)。
異步和多線程并不是一個(gè)同等關(guān)系,異步是最終目的,多線程只是我們實(shí)現(xiàn)異步的一種手段

二.iOS-GCD

Grand Central Dispatch簡稱GCD.好處此處不再多言,直接上代碼

//定義四個(gè)調(diào)度任務(wù),打印當(dāng)前線程數(shù)據(jù)

let item1 = DispatchWorkItem {
    for i in 0...4{
        print("item1 -> \(i)  thread: \(Thread.current)")
    }
}

let item2 = DispatchWorkItem {
    for i in 0...4{
        print("item2 -> \(i)  thread: \(Thread.current)")
    }
}

let item3 = DispatchWorkItem {
    for i in 0...4{
        print("item3 -> \(i)  thread: \(Thread.current)")
    }
}

let item4 = DispatchWorkItem {
    for i in 0...4{
        print("item4 -> \(i)  thread: \(Thread.current)")
    }
}

1.Main queue與主線程關(guān)聯(lián)的調(diào)度隊(duì)列,是一種串行隊(duì)列(Serial),與UI相關(guān)的操作必須放在Main queue中執(zhí)行

  • 主隊(duì)列(串行)追加異步任務(wù) => 按順序打印
let mainQueue = DispatchQueue.main
mainQueue.async(execute: item1)
mainQueue.async(execute: item2)
mainQueue.async(execute: item3)
mainQueue.async(execute: item4)
//item1 -> 0  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item1 -> 1  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item1 -> 2  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item1 -> 3  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item1 -> 4  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item2 -> 0  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item2 -> 1  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item2 -> 2  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item2 -> 3  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item2 -> 4  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item3 -> 0  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item3 -> 1  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item3 -> 2  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item3 -> 3  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item3 -> 4  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item4 -> 0  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item4 -> 1  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item4 -> 2  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item4 -> 3  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
//item4 -> 4  thread: <NSThread: 0x600000f5c440>{number = 1, name = main}
  • 主隊(duì)列(串行)追加同步任務(wù),會引起死鎖
    原因分析:
    如果在主線程中運(yùn)用主隊(duì)列同步,也就是把任務(wù)放到了主線程的隊(duì)列中。而同步對于任務(wù)是立刻執(zhí)行的,那么當(dāng)把一個(gè)任務(wù)放進(jìn)主隊(duì)列時(shí),它就會立馬執(zhí)行。
    可是主線程現(xiàn)在正在處理 syncMain 方法,任務(wù)需要等 syncMain 執(zhí)行完才能執(zhí)行。syncMain 執(zhí)行到第一個(gè)任務(wù)的時(shí)候,又要等第一個(gè)任務(wù)執(zhí)行完才能往下執(zhí)行第二個(gè)和第三個(gè)任務(wù)。這樣 syncMain 方法和第一個(gè)任務(wù)就開始了互相等待,形成了死鎖。
func syncMain(){
      let mainQueue = DispatchQueue.main
      mainQueue.sync(execute: item1)
}

2.Global queue運(yùn)行在后臺線程,是系統(tǒng)內(nèi)共享的全局隊(duì)列,是一種并行隊(duì)列

  • 全局隊(duì)列(并行)追加異步任務(wù) => 隨機(jī)打印
let globalQueue = DispatchQueue.global()
globalQueue.async(execute: item1)
globalQueue.async(execute: item2)
globalQueue.async(execute: item3)
globalQueue.async(execute: item4)
//item1 -> 0  thread: <NSThread: 0x60000148f200>{number = 7, name = (null)}
//item4 -> 0  thread: <NSThread: 0x600001496440>{number = 8, name = (null)}
//item3 -> 0  thread: <NSThread: 0x6000014846c0>{number = 9, name = (null)}
//item2 -> 0  thread: <NSThread: 0x600001496500>{number = 10, name = (null)}
//item1 -> 1  thread: <NSThread: 0x60000148f200>{number = 7, name = (null)}
//item3 -> 1  thread: <NSThread: 0x6000014846c0>{number = 9, name = (null)}
//item1 -> 2  thread: <NSThread: 0x60000148f200>{number = 7, name = (null)}
//item2 -> 1  thread: <NSThread: 0x600001496500>{number = 10, name = (null)}
//item4 -> 1  thread: <NSThread: 0x600001496440>{number = 8, name = (null)}
//item1 -> 3  thread: <NSThread: 0x60000148f200>{number = 7, name = (null)}
//item4 -> 2  thread: <NSThread: 0x600001496440>{number = 8, name = (null)}
//item1 -> 4  thread: <NSThread: 0x60000148f200>{number = 7, name = (null)}
//item4 -> 3  thread: <NSThread: 0x600001496440>{number = 8, name = (null)}
//item4 -> 4  thread: <NSThread: 0x600001496440>{number = 8, name = (null)}
//item3 -> 2  thread: <NSThread: 0x6000014846c0>{number = 9, name = (null)}
//item3 -> 3  thread: <NSThread: 0x6000014846c0>{number = 9, name = (null)}
//item2 -> 2  thread: <NSThread: 0x600001496500>{number = 10, name = (null)}
//item3 -> 4  thread: <NSThread: 0x6000014846c0>{number = 9, name = (null)}
//item2 -> 3  thread: <NSThread: 0x600001496500>{number = 10, name = (null)}
//item2 -> 4  thread: <NSThread: 0x600001496500>{number = 10, name = (null)}
  • 全局隊(duì)列(并行)追加同步任務(wù),按順序打印
let globalQueue = DispatchQueue.global()
globalQueue.sync(execute: item1)
globalQueue.sync(execute: item2)
globalQueue.sync(execute: item3)
globalQueue.sync(execute: item4)

//item1 -> 0  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item1 -> 1  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item1 -> 2  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item1 -> 3  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item1 -> 4  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item2 -> 0  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item2 -> 1  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item2 -> 2  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item2 -> 3  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item2 -> 4  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item3 -> 0  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item3 -> 1  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item3 -> 2  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item3 -> 3  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item3 -> 4  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item4 -> 0  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item4 -> 1  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item4 -> 2  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item4 -> 3  thread: <NSThread: 0x600001044a80>{number = 1, name = main}
//item4 -> 4  thread: <NSThread: 0x600001044a80>{number = 1, name = main}

3.Custom queue運(yùn)行在后臺線程,默認(rèn)是串行隊(duì)列(Serial),初始化時(shí)指定attributes參數(shù)為 .concurrent,可以創(chuàng)建成并行隊(duì)列(Concurrent)

串行隊(duì)列(Serial)

  • 自定義串行隊(duì)列追加異步任務(wù) => 按順序打印

let serialQueue = DispatchQueue(label: "serial")
serialQueue.async(execute: item1)
serialQueue.async(execute: item2)
serialQueue.async(execute: item3)
serialQueue.async(execute: item4)
//item1 -> 0  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item1 -> 1  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item1 -> 2  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item1 -> 3  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item1 -> 4  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item2 -> 0  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item2 -> 1  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item2 -> 2  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item2 -> 3  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item2 -> 4  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item3 -> 0  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item3 -> 1  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item3 -> 2  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item3 -> 3  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item3 -> 4  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item4 -> 0  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item4 -> 1  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item4 -> 2  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item4 -> 3  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
//item4 -> 4  thread: <NSThread: 0x600001c8e4c0>{number = 6, name = (null)}
  • 自定義串行隊(duì)列追加同步任務(wù),按順序打印
let serialQueue = DispatchQueue(label: "serial")
serialQueue.sync(execute: item1)
serialQueue.sync(execute: item2)
serialQueue.sync(execute: item3)
serialQueue.sync(execute: item4)
//item1 -> 0  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item1 -> 1  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item1 -> 2  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item1 -> 3  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item1 -> 4  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item2 -> 0  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item2 -> 1  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item2 -> 2  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item2 -> 3  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item2 -> 4  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item3 -> 0  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item3 -> 1  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item3 -> 2  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item3 -> 3  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item3 -> 4  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item4 -> 0  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item4 -> 1  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item4 -> 2  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item4 -> 3  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}
//item4 -> 4  thread: <NSThread: 0x6000004e08c0>{number = 1, name = main}

并行隊(duì)列(Concurrent)

  • 自定義并行隊(duì)列追加異步任務(wù) => 隨機(jī)打印
let concurrentQueue = DispatchQueue(label: "concurrent", attributes: .concurrent)
concurrentQueue.async(execute: item1)
concurrentQueue.async(execute: item2)
concurrentQueue.async(execute: item3)
concurrentQueue.async(execute: item4)
//item1 -> 0  thread: <NSThread: 0x6000035c6940>{number = 6, name = (null)}
//item3 -> 0  thread: <NSThread: 0x6000035cc700>{number = 8, name = (null)}
//item2 -> 0  thread: <NSThread: 0x6000035ce0c0>{number = 5, name = (null)}
//item4 -> 0  thread: <NSThread: 0x6000035c1100>{number = 3, name = (null)}
//item1 -> 1  thread: <NSThread: 0x6000035c6940>{number = 6, name = (null)}
//item4 -> 1  thread: <NSThread: 0x6000035c1100>{number = 3, name = (null)}
//item3 -> 1  thread: <NSThread: 0x6000035cc700>{number = 8, name = (null)}
//item2 -> 1  thread: <NSThread: 0x6000035ce0c0>{number = 5, name = (null)}
//item4 -> 2  thread: <NSThread: 0x6000035c1100>{number = 3, name = (null)}
//item3 -> 2  thread: <NSThread: 0x6000035cc700>{number = 8, name = (null)}
//item1 -> 2  thread: <NSThread: 0x6000035c6940>{number = 6, name = (null)}
//item4 -> 3  thread: <NSThread: 0x6000035c1100>{number = 3, name = (null)}
//item2 -> 2  thread: <NSThread: 0x6000035ce0c0>{number = 5, name = (null)}
//item1 -> 3  thread: <NSThread: 0x6000035c6940>{number = 6, name = (null)}
//item3 -> 3  thread: <NSThread: 0x6000035cc700>{number = 8, name = (null)}
//item4 -> 4  thread: <NSThread: 0x6000035c1100>{number = 3, name = (null)}
//item2 -> 3  thread: <NSThread: 0x6000035ce0c0>{number = 5, name = (null)}
//item1 -> 4  thread: <NSThread: 0x6000035c6940>{number = 6, name = (null)}
//item3 -> 4  thread: <NSThread: 0x6000035cc700>{number = 8, name = (null)}
//item2 -> 4  thread: <NSThread: 0x6000035ce0c0>{number = 5, name = (null)}
  • 自定義并行隊(duì)列追加同步任務(wù),按順序打印
let concurrentQueue = DispatchQueue(label: "concurrent", attributes: .concurrent)
concurrentQueue.sync(execute: item1)
concurrentQueue.sync(execute: item2)
concurrentQueue.sync(execute: item3)
concurrentQueue.sync(execute: item4)
//item1 -> 0  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item1 -> 1  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item1 -> 2  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item1 -> 3  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item1 -> 4  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item2 -> 0  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item2 -> 1  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item2 -> 2  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item2 -> 3  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item2 -> 4  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item3 -> 0  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item3 -> 1  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item3 -> 2  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item3 -> 3  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item3 -> 4  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item4 -> 0  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item4 -> 1  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item4 -> 2  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item4 -> 3  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
//item4 -> 4  thread: <NSThread: 0x600003fa0800>{number = 1, name = main}
image.png

三.死鎖分析

(1). 主線程中執(zhí)行, 主隊(duì)列(串行)+同步任務(wù),會引起死鎖.

原因分析:
主隊(duì)列只能運(yùn)行在主線程。主隊(duì)列本身任務(wù)與當(dāng)前同步任務(wù)相互等待

自定義串行隊(duì)列+同步任務(wù),不會死鎖

原因分析:
自定義串行隊(duì)列內(nèi)本身沒有任務(wù),加入同步任務(wù)后,按順序執(zhí)行,所以不會死鎖。

自定義并行隊(duì)列+同步任務(wù) 不會死鎖;
自定義并行隊(duì)列+異步任務(wù),不會死鎖

原因分析:
并行隊(duì)列有能力啟動(dòng)主線程和后臺線程(可以啟動(dòng)一個(gè)或多個(gè)后臺線程,部分設(shè)備上可以啟動(dòng)多達(dá)64個(gè)后臺線程)。 并行隊(duì)列遇到同步任務(wù),會自動(dòng)安排在主線程執(zhí)行,雖然是并行隊(duì)列,也只能順序執(zhí)行;遇到異步任務(wù),自動(dòng)安排在后臺線程執(zhí)行,所以不會死鎖。

(2). 其他死鎖.

自定義串行隊(duì)列嵌套同步任務(wù),會引起死鎖

原因分析:
與主隊(duì)列+同步任務(wù)原因類似,本身已經(jīng)加入任務(wù)1執(zhí)行(不論是異步還是同步),任務(wù)1中又需要執(zhí)行同步任務(wù)2,但是任務(wù)2(同步任務(wù))需要等任務(wù)1執(zhí)行完才能執(zhí)行;任務(wù)1又需要等任務(wù)2執(zhí)行完才算執(zhí)行完任務(wù)1.相互等待

let serialQueue = DispatchQueue(label: "serial")
//死鎖
serialQueue.sync {
    print("同步執(zhí)行  thread: \(Thread.current)")//任務(wù)1
    serialQueue.sync {
        print("同步執(zhí)行  thread: \(Thread.current)")//任務(wù)2
    }
}
//死鎖
serialQueue.async {
    print("異步執(zhí)行  thread: \(Thread.current)")//任務(wù)1
    serialQueue.sync {
        print("同步執(zhí)行  thread: \(Thread.current)")//任務(wù)2
    }
}
自定義串行隊(duì)列嵌套異步任務(wù),不會引起死鎖

原因分析:
同步嵌套異步:本身已經(jīng)加入任務(wù)1同步執(zhí)行,任務(wù)2是異步任務(wù)加入子線程執(zhí)行,任務(wù)3同步執(zhí)行;
異步嵌套異步:任務(wù)1,任務(wù)2是異步任務(wù)都加入子線程執(zhí)行

//不會引起死鎖
serialQueue.sync {
    print("同步執(zhí)行  thread: \(Thread.current)")//任務(wù)1
    serialQueue.async {
        print("異步執(zhí)行  thread: \(Thread.current)")//任務(wù)2
    }
    print("同步執(zhí)行  thread: \(Thread.current)")//任務(wù)3
}
//同步執(zhí)行  thread: <NSThread: 0x60000356c800>{number = 1, name = main}
//同步執(zhí)行  thread: <NSThread: 0x60000356c800>{number = 1, name = main}
//異步執(zhí)行  thread: <NSThread: 0x600003569940>{number = 6, name = (null)}

//不會引起死鎖
serialQueue.async {
    print("異步執(zhí)行  thread: \(Thread.current)")
    serialQueue.async {
        print("異步執(zhí)行  thread: \(Thread.current)")
    }
}
//異步執(zhí)行  thread: <NSThread: 0x600003ff9100>{number = 4, name = (null)}
//異步執(zhí)行  thread: <NSThread: 0x600003ff9100>{number = 4, name = (null)}
并行隊(duì)列嵌套同步任務(wù),不會引起死鎖

原因分析:異步嵌套同步:任務(wù)1,任務(wù)2是異步任務(wù)都加入子線程執(zhí)行;
同步嵌套同步:任務(wù)1,任務(wù)2都在主線程中順序執(zhí)行
同步嵌套異步:任務(wù)1在主線程中執(zhí)行,任務(wù)2在子線程執(zhí)行

//自定義并行隊(duì)列(全局并行隊(duì)列結(jié)果一樣)
let concurrentQueue = DispatchQueue(label: "concurrent", attributes: .concurrent)
//不會引起死鎖
concurrentQueue.async {
    print("異步執(zhí)行  thread: \(Thread.current)")//任務(wù)1
    concurrentQueue.sync {
        print("同步執(zhí)行  thread: \(Thread.current)")//任務(wù)2
    }
}
//異步執(zhí)行  thread: <NSThread: 0x6000033b5900>{number = 7, name = (null)}
//同步執(zhí)行  thread: <NSThread: 0x6000033b5900>{number = 7, name = (null)}

//不會引起死鎖
concurrentQueue.sync {
    print("同步執(zhí)行  thread: \(Thread.current)")//任務(wù)1
    concurrentQueue.sync {
        print("同步執(zhí)行  thread: \(Thread.current)")//任務(wù)2
    }
}
//同步執(zhí)行  thread: <NSThread: 0x600000064a80>{number = 1, name = main}
//同步執(zhí)行  thread: <NSThread: 0x600000064a80>{number = 1, name = main}

//不會引起死鎖
concurrentQueue.sync {
    print("同步執(zhí)行  thread: \(Thread.current)")//任務(wù)1
    concurrentQueue.async {
        print("異步執(zhí)行  thread: \(Thread.current)")//任務(wù)2
    }
}
//同步執(zhí)行  thread: <NSThread: 0x600000d088c0>{number = 1, name = main}
//異步執(zhí)行  thread: <NSThread: 0x600000d0d000>{number = 3, name = (null)}
//不會引起死鎖
concurrentQueue.async {
    print("異步執(zhí)行  thread: \(Thread.current)")
    concurrentQueue.async {
        print("異步執(zhí)行  thread: \(Thread.current)")
    }
}
//異步執(zhí)行  thread: <NSThread: 0x600003f593c0>{number = 5, name = (null)}
//異步執(zhí)行  thread: <NSThread: 0x600003f52440>{number = 8, name = (null)}
image.png

四.實(shí)例理解

如何理解同步/異步,串行/并行,這里引用一個(gè)例子:

http://m.itdecent.cn/p/2d57c72016c6
假設(shè)現(xiàn)在有 一堆人要穿過一道門禁,這道門禁總共有 10 個(gè)入口和一個(gè)特殊通道,管理員可以決定同一時(shí)間打開幾個(gè)入口,可以決定同一時(shí)間讓一個(gè)人單獨(dú)通過還是多個(gè)人一起通過。不過默認(rèn)情況下,管理員只開啟一個(gè)入口,且一個(gè)通道一次只能通過一個(gè)人。

這個(gè)故事里,人好比是 任務(wù),管理員好比是 系統(tǒng),入口則代表 線程。
5 個(gè)人表示有 5 個(gè)任務(wù),10 個(gè)入口代表 10 條線程。

串行隊(duì)列 好比是 5 個(gè)人排成一支長隊(duì)。
并發(fā)隊(duì)列 好比是 5 個(gè)人排成多支隊(duì)伍,比如 2 隊(duì),或者 3 隊(duì)。
同步任務(wù) 好比是管理員只開啟了一個(gè)入口(當(dāng)前線程)。
異步任務(wù) 好比是管理員同時(shí)開啟了多個(gè)入口(當(dāng)前線程 + 新開的線程)。
主隊(duì)列 好比是特殊通道(老幼病殘?jiān)袑S?,僅有1個(gè)

主隊(duì)列+異步 可以理解為: 特殊通道只有一個(gè),來了很多正常人,但是無法開啟普通通道,隊(duì)伍只能通過特殊通道依次通過
主隊(duì)列+同步 可以理解為:特殊通道隊(duì)伍中的第一名是一個(gè)普通人第二名是一個(gè)老奶奶,普通人無法通過特殊通道,需要等老幼病殘?jiān)袃?yōu)先通過;可是奶奶排在一個(gè)普通人的后面 他們無法交換順序,只能互相等待 ,死鎖
(全局/自定義)并行+異步 可以理解為:現(xiàn)在管理員開啟了多個(gè)入口(比如 3 個(gè)入口),5 個(gè)人排成了多支隊(duì)伍(比如 3 支隊(duì)伍),這樣這 5 個(gè)人就可以 3 個(gè)人同時(shí)一起穿過門禁了,隨機(jī)通過
(全局/自定義)并行+同步 可以理解為:現(xiàn)在管理員只開啟了 1 個(gè)入口,5 個(gè)人排成了多支隊(duì)伍。雖然這 5 個(gè)人排成了多支隊(duì)伍,但是只開了 1 個(gè)入口,這 5 個(gè)人雖然都想快點(diǎn)過去,但是 1 個(gè)入口一次只能過 1 個(gè)人,所以大家就只好一個(gè)接一個(gè)走過去了,表現(xiàn)的結(jié)果就是:順次通過入口。
自定義串行+異步 可以理解為:現(xiàn)在管理員只開啟了 1 個(gè)入口,5 個(gè)人排成了1支隊(duì)伍。大家順次通過入口。
自定義串行+同步 可以理解為:現(xiàn)在管理員只開啟了 3個(gè)入口,5 個(gè)人排成了1支隊(duì)伍。大家還是順次通過一個(gè)入口。

串行+嵌套同步任務(wù) 可以理解為:
串行+同步+嵌套同步: 管理員只開啟了一個(gè)入口, 2支隊(duì)伍排在這一個(gè)入口,互相謙讓,相互等待,死鎖
串行+異步+嵌套同步: 管理員開啟了多開了1個(gè)入口, 2支隊(duì)伍,都排在了這個(gè)入口處處, 互相謙讓,相互等待,死鎖
串行+嵌套異步任務(wù) 可以理解為:
串行+同步/異步+嵌套異步: 管理員開啟了一個(gè)入口1, 隊(duì)伍1排在入口1處;又來了一個(gè)隊(duì)伍,管理員開啟了入口2,隊(duì)伍2排在了入口2處.
并行+嵌套同步任務(wù) 可以理解為:
并行+同步+嵌套同步: 管理員只開啟了默認(rèn)的一個(gè)入口, 隊(duì)伍1來了排在入口處,又來了一支隊(duì)伍2,只能排在隊(duì)伍1后面
并行+異步+嵌套同步: 管理員開啟了多開了1個(gè)入口, 隊(duì)伍1來了排在入口處,又來了一支隊(duì)伍2,只能排在隊(duì)伍1后面
并行+嵌套異步任務(wù) 可以理解為:
并行+同步+嵌套異步: 管理員只開啟了默認(rèn)的一個(gè)入口, 隊(duì)伍1來了排在入口處,又來了一支隊(duì)伍2,管理員又開啟了一個(gè)入口
并行+異步+嵌套異步: 隊(duì)伍1來了,管理員為其開了一個(gè)入口; 又來了一支隊(duì)伍2,管理員又開啟了一個(gè)入口

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

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

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