GCD隊列+任務(wù)(OC&Swift)

說明:本文主要用于個人能力的提高讳侨,主要參考于簡書搀捷,Swift版本為3.0

1. 簡介

什么是GCD呢艾少?我們先看看百度百科的解釋了解下概念

引用百度百科
Grand Central Dispatch (GCD) 是Apple開發(fā)的一個多核編程的較新的解決方法默怨。它主要用于優(yōu)化應(yīng)用程序以支持多核處理器以及其他對稱多處理系統(tǒng)樟氢。它是一個在線程池模式的基礎(chǔ)上執(zhí)行的并行任務(wù)。在Mac OS X 10.6雪豹中首次推出镇饺,也可在IOS 4及以上版本使用。

為什么要用GCD呢送讲?

因為GCD有很多好處奸笤,具體如下:

  • GCD可用于多核的并行運算
  • GCD會自動利用更多的CPU內(nèi)核(比如雙核惋啃、四核)
  • GCD會自動管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)监右、銷毀線程)
  • 程序員只需要告訴GCD想要執(zhí)行什么任務(wù)边灭,不需要編寫任何線程管理代碼

既然GCD有這么多的好處,那么下面我們就來系統(tǒng)的學(xué)習(xí)一下GCD的使用方法健盒。

2.任務(wù)和隊列

學(xué)習(xí)GCD之前绒瘦,先來了解GCD中兩個核心概念:任務(wù)和隊列

任務(wù): 就是執(zhí)行操作的意思,換句話說就是你在線程中執(zhí)行的那段代碼扣癣。在GCD中是放在block中的惰帽,swift是放在閉包中的。執(zhí)行任務(wù)有兩種方式:同步執(zhí)行異步執(zhí)行父虑。兩者的主要區(qū)別是:是否具備開啟新線程的能力该酗。

  • 同步執(zhí)行(sync):只能在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力
  • 異步執(zhí)行(async):可以在新的線程中執(zhí)行任務(wù)士嚎,具備開啟新線程的能力

隊列:這里的隊列指任務(wù)隊列呜魄,即用來存放任務(wù)的隊列。隊列是一種特殊的線性表莱衩,采用FIFO(先進(jìn)先出)的原則爵嗅,即新任務(wù)總是被插入到隊列的末尾,而讀取任務(wù)的時候總是從隊列的頭部開始讀取笨蚁。每讀取一個任務(wù)睹晒,則從隊列中釋放一個任務(wù)。在GCD中有兩種隊列:串行隊列并行隊列赚窃。

  • 并行隊列(Concurrent Dispatch Queue):可以讓多個任務(wù)并行(同時)執(zhí)行(自動開啟多個線程同時執(zhí)行任務(wù))
    • 并行功能只有在異步(dispatch_async)函數(shù)下才有效
  • 串行隊列(Serial Dispatch Queue):讓任務(wù)一個接著一個地執(zhí)行(一個任務(wù)執(zhí)行完畢后册招,再執(zhí)行下一個任務(wù))

3.GCD的使用步驟

GCD的使用步驟其實很簡單,只有兩步勒极。

  1. 創(chuàng)建一個隊列(串行隊列或并行隊列)
  2. 將任務(wù)添加到隊列中是掰,然后系統(tǒng)就會根據(jù)任務(wù)類型執(zhí)行任務(wù)(同步執(zhí)行或異步執(zhí)行)

下面來看看隊列的創(chuàng)建和任務(wù)的創(chuàng)建方法室奏。

1. 隊列的創(chuàng)建方法

OC版本:

  • 可以使用dispatch_queue_create來創(chuàng)建對象妨蛹,需要傳入兩個參數(shù)讥邻,第一個參數(shù)表示隊列的唯一標(biāo)識符责蝠,用于DEBUG矩欠,可為空钮热;第二個參數(shù)用來識別是串行隊列還是并行隊列髓棋。DISPATCH_QUEUE_SERIAL表示串行隊列喧锦,DISPATCH_QUEUE_CONCURRENT表示并行隊列昨忆。
// 串行隊列的創(chuàng)建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
// 并行隊列的創(chuàng)建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT); 
  • 對于并行隊列丁频,還可以使用dispatch_get_global_queue來創(chuàng)建全局并行隊列。GCD默認(rèn)提供了全局的并行隊列,需要傳入兩個參數(shù)席里。第一個參數(shù)表示隊列優(yōu)先級叔磷,一般用DISPATCH_QUEUE_PRIORITY_DEFAULT。第二個參數(shù)暫時沒用奖磁,用0即可改基。

Swift版本:

  • 在使用Swift編碼時,可以使用DispatchQueue來創(chuàng)建對象咖为,第一個參數(shù)與OC相同秕狰,為標(biāo)識符,其他參數(shù)均可省略躁染。當(dāng)僅有一個label參數(shù)時鸣哀,默認(rèn)為串行隊列,當(dāng)設(shè)置了attributes.concurrent時為并行隊列褐啡。
// 創(chuàng)建串行隊列
let queue = DispatchQueue(label: "test.queue")
// 創(chuàng)建并行隊列
let queue = DispatchQueue(label: "test.queue", attributes: .concurrent)

2. 任務(wù)的創(chuàng)建方法

OC版本:

// 同步執(zhí)行任務(wù)創(chuàng)建方法
dispatch_sync(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);  // 這里放任務(wù)代碼
});
    
// 異步執(zhí)行任務(wù)創(chuàng)建方法
dispatch_async(queue, ^{
    NSLog(@"%@",[NSThread currentThread]);  // 這里放任務(wù)代碼
});

Swift版本:

// 同步執(zhí)行任務(wù)創(chuàng)建方法
queue.sync {
    print(Thread.current)
}
// 異步執(zhí)行任務(wù)創(chuàng)建方法
queue.async {
    print(Thread.current)
}

雖然使用GCD只有兩步诺舔,但是既然我們有兩種隊列,兩種任務(wù)執(zhí)行方式备畦,那么我們就有了四種不同的組合方式低飒。這四種不同的組合方式是:

  1. 并行隊列 + 同步執(zhí)行
  2. 并行隊列 + 異步執(zhí)行
  3. 串行隊列 + 同步執(zhí)行
  4. 串行隊列 + 異步執(zhí)行

實際上我們還有一種特殊的主隊列,那就有六種不同的組合方式了

  1. 主隊列 + 同步執(zhí)行
  2. 主隊列 + 異步執(zhí)行

那么這幾種不同組合方式有什么區(qū)別呢懂盐,這里為了方便褥赊,先上結(jié)果,再來講解莉恼。為圖省事拌喉,直接查看表格結(jié)果,然后可以跳過4. GCD的基本使用 了俐银。

并行隊列 串行隊列 主隊列
同步(sync) 沒有開啟新線程尿背,串行執(zhí)行任務(wù) 沒有開啟新線程,串行執(zhí)行任務(wù) 沒有開啟新線程捶惜,串行執(zhí)行任務(wù)
異步(async) 有開啟新線程田藐,并行執(zhí)行任務(wù) 有開啟新線程(1條),串行執(zhí)行任務(wù) 沒有開啟新線程吱七,串行執(zhí)行任務(wù)

4. GCD的基本使用

先來講講并行隊列的兩種使用方法汽久。

1. 并行隊列 + 同步執(zhí)行

  • 不會開啟新線程,執(zhí)行完一個任務(wù)踊餐,再執(zhí)行下一個任務(wù)
    OC版本:
- (void)syncConcurrentMethod{
    NSLog(@"syncConcurrentMethod---begin");
    
    dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"syncConcurrentMethod---end");
}

輸出結(jié)果:
2017-09-19 10:57:34.223 OC-GCD[1824:54181] syncConcurrentMethod---begin
2017-09-19 10:57:34.223 OC-GCD[1824:54181] 1------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.223 OC-GCD[1824:54181] 1------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.223 OC-GCD[1824:54181] 2------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.223 OC-GCD[1824:54181] 2------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.224 OC-GCD[1824:54181] 3------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.224 OC-GCD[1824:54181] 3------<NSThread: 0x61800006d000>{number = 1, name = main}
2017-09-19 10:57:34.224 OC-GCD[1824:54181] syncConcurrentMethod---end

Swift版本:

    func syncConcurrentMethod() {
        print("syncConcurrentMethod---begin")
        
        let queue = DispatchQueue(label: "test.queue", attributes: .concurrent)
        
        queue.sync {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("syncConcurrentMethod---end")
    }

輸出結(jié)果:
syncConcurrentMethod---begin
1------ <NSThread: 0x61000006a440>{number = 1, name = main}
1------ <NSThread: 0x61000006a440>{number = 1, name = main}
2------ <NSThread: 0x61000006a440>{number = 1, name = main}
2------ <NSThread: 0x61000006a440>{number = 1, name = main}
3------ <NSThread: 0x61000006a440>{number = 1, name = main}
3------ <NSThread: 0x61000006a440>{number = 1, name = main}
syncConcurrentMethod---end

  • 并行隊列 + 同步執(zhí)行中可以看到景醇,所有任務(wù)都是在主線程中執(zhí)行的,由于只有一個線程吝岭,所以任務(wù)只能一個一個執(zhí)行三痰。
  • 同事我們還可以看到吧寺,所有任務(wù)都在打印的syncConcurrentMethod---beginsyncConcurrentMethod---end之間,這說明任務(wù)是添加到隊列中馬上執(zhí)行的酒觅。

2. 并行隊列 + 異步執(zhí)行

  • 可同時開啟多線程撮执,任務(wù)交替執(zhí)行

OC版本:

- (void)asyncConcurrentMethod{
    NSLog(@"asyncConcurrentMethod---begin");
    
    dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"asyncConcurrentMethod---end");
}

輸出結(jié)果:
2017-09-19 11:16:35.521 OC-GCD[2301:67293] asyncConcurrentMethod---begin
2017-09-19 11:16:35.521 OC-GCD[2301:67293] asyncConcurrentMethod---end
2017-09-19 11:16:35.521 OC-GCD[2301:67348] 1------<NSThread: 0x608000073e00>{number = 3, name = (null)}
2017-09-19 11:16:35.521 OC-GCD[2301:67719] 2------<NSThread: 0x6000000787c0>{number = 4, name = (null)}
2017-09-19 11:16:35.521 OC-GCD[2301:67720] 3------<NSThread: 0x6180000790c0>{number = 5, name = (null)}
2017-09-19 11:16:35.522 OC-GCD[2301:67348] 1------<NSThread: 0x608000073e00>{number = 3, name = (null)}
2017-09-19 11:16:35.522 OC-GCD[2301:67719] 2------<NSThread: 0x6000000787c0>{number = 4, name = (null)}
2017-09-19 11:16:35.522 OC-GCD[2301:67720] 3------<NSThread: 0x6180000790c0>{number = 5, name = (null)}

Swift版本:

func asyncConcurrentMethod() {
        print("asyncConcurrentMethod---begin")
        
        let queue = DispatchQueue(label: "test.queue", attributes: .concurrent)
        
        queue.async {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("asyncConcurrentMethod---end")
    }

輸出結(jié)果:
asyncConcurrentMethod---begin
asyncConcurrentMethod---end
1------ <NSThread: 0x61000007e700>{number = 3, name = (null)}
2------ <NSThread: 0x60800007eac0>{number = 4, name = (null)}
3------ <NSThread: 0x60800007ec00>{number = 5, name = (null)}
1------ <NSThread: 0x61000007e700>{number = 3, name = (null)}
2------ <NSThread: 0x60800007eac0>{number = 4, name = (null)}
3------ <NSThread: 0x60800007ec00>{number = 5, name = (null)}

  • 并行隊列 + 異步執(zhí)行中可以看出,除了主線程舷丹,又新開啟了3個新線程,并且任務(wù)是交替著同時進(jìn)行的蜓肆。
  • 另一方面可以看出颜凯,所有任務(wù)是在打印的asyncConcurrentMethod---beginasyncConcurrentMethod---end之后才開始執(zhí)行的。說明任務(wù)不是馬上執(zhí)行仗扬,而是將所有任務(wù)添加到隊列之后才開始異步執(zhí)行的症概。

3. 串行隊列 + 同步執(zhí)行

  • 不會開啟新線程,在當(dāng)前線程執(zhí)行任務(wù)早芭。任務(wù)是串行的彼城,執(zhí)行完一個任務(wù),再執(zhí)行下一個任務(wù)退个。
    OC版本:
- (void) syncSerialMethod {
    NSLog(@"syncSerialMethod---begin");
    
    dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"syncSerialMethod---end");
}

輸出結(jié)果:
2017-09-19 11:35:00.774 OC-GCD[2699:78730] syncSerialMethod---begin
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 1------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 1------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 2------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 2------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.775 OC-GCD[2699:78730] 3------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.776 OC-GCD[2699:78730] 3------<NSThread: 0x6100000641c0>{number = 1, name = main}
2017-09-19 11:35:00.776 OC-GCD[2699:78730] syncSerialMethod---end
Swift版本:

func syncSerialMethod() {
        
        print("syncSerialMethod---begin")
        
        let queue = DispatchQueue(label: "test.queue")
        
        queue.sync {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("syncSerialMethod---end")
        
    }

輸出結(jié)果:
syncSerialMethod---begin
1------ <NSThread: 0x6080000757c0>{number = 1, name = main}
1------ <NSThread: 0x6080000757c0>{number = 1, name = main}
2------ <NSThread: 0x6080000757c0>{number = 1, name = main}
2------ <NSThread: 0x6080000757c0>{number = 1, name = main}
3------ <NSThread: 0x6080000757c0>{number = 1, name = main}
3------ <NSThread: 0x6080000757c0>{number = 1, name = main}
syncSerialMethod---end

  • 串行隊列 + 同步執(zhí)行可以看到募壕,所有任務(wù)都是在主線程中執(zhí)行的,并沒有開啟新的線程语盈。而且由于串行隊列舱馅,所以按順序一個一個執(zhí)行。
  • 同時我們還可以看到刀荒,所有任務(wù)都在打印的syncSerialMethod---beginsyncSerialMethod---end之間代嗤,說明任務(wù)是添加到隊列中,并馬上執(zhí)行的缠借。

4. 串行隊列 + 異步執(zhí)行

  • 會開啟新線程干毅,但是因為任務(wù)是串行的,執(zhí)行完一個任務(wù)泼返,再執(zhí)行下一個任務(wù)
    OC版本:
- (void) asyncSerialMethod{
    NSLog(@"asyncSerialMethod---begin");
    
    dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"asyncSerialMethod---end");
}

輸出結(jié)果:
2017-09-19 11:54:29.808 OC-GCD[3018:88451] asyncSerialMethod---begin
2017-09-19 11:54:29.808 OC-GCD[3018:88451] asyncSerialMethod---end
2017-09-19 11:54:29.808 OC-GCD[3018:88506] 1------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 1------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 2------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 2------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 3------<NSThread: 0x600000068940>{number = 3, name = (null)}
2017-09-19 11:54:29.809 OC-GCD[3018:88506] 3------<NSThread: 0x600000068940>{number = 3, name = (null)}

Swift版本:

func asyncSerialMethod() {
        
        print("asyncSerialMethod---begin")
        
        let queue = DispatchQueue(label: "test.queue")
        
        queue.async {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("asyncSerialMethod---end")
        
    }

輸出結(jié)果:
asyncSerialMethod---begin
asyncSerialMethod---end
1------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
1------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
2------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
2------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
3------ <NSThread: 0x600000267c80>{number = 3, name = (null)}
3------ <NSThread: 0x600000267c80>{number = 3, name = (null)}

  • 串行隊列 + 異步執(zhí)行可以看到硝逢,開啟了一條新線程,但是任務(wù)還是串行符隙,所以任務(wù)是一個一個執(zhí)行趴捅。
  • 另一方面可以看出,所有哦任務(wù)是在打印的asyncSerialMethod---beginasyncSerialMethod---end之后才開始執(zhí)行的霹疫。說明任務(wù)不是馬上執(zhí)行拱绑,而是將所有任務(wù)添加到隊列之后才開始異步執(zhí)行的。

然后講講剛才提到過的特殊隊列——主隊列

  • 主隊列:GCD自帶的一種特殊的串行隊列
    • 所有放在主隊列中的任務(wù)丽蝎,都會放到主線程中執(zhí)行
    • OC可以使用dispatch_get_main_queue()獲得主隊列猎拨,Swift可以使用DispatchQueue.main獲得

再來看看主隊列的兩種組合方式

5. 主隊列 + 同步執(zhí)行

  • 相互等待膀藐,造成死鎖(在主線程中調(diào)用時)

OC版本:

- (void)syncMainMethod{
    NSLog(@"syncMainMethod---begin");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_sync(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"syncMainMethod---end");
}

輸出結(jié)果:
2017-09-19 14:20:14.826 OC-GCD[4057:146416] syncMainMethod---begin
(lldb)

Swift版本:

func syncMainMethod() {
        
        print("syncMainMethod---begin")
        
        let queue = DispatchQueue.main
        
        queue.sync {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.sync {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("syncMainMethod---end")
        
    }

輸出結(jié)果:
syncMainMethod---begin
(lldb)

這時候,我們可以發(fā)現(xiàn)红省,在主線程中使用主隊列 + 同步執(zhí)行额各,任務(wù)不再執(zhí)行了,而syncMainMethod---end也沒有打印了吧恃,這是什么原因?qū)е碌哪兀?/p>

這是因為我們在主線中執(zhí)行這段代碼虾啦。我們把任務(wù)放到了主隊列中,也就是放到了主線程的隊列中痕寓。而同步執(zhí)行有個特點傲醉,就是對于任務(wù)是立馬執(zhí)行的。那么當(dāng)我們把第一個任務(wù)放進(jìn)主隊列中呻率,它會立即執(zhí)行硬毕。但是對于主線程現(xiàn)在正在處理syncMainMethod方法,而任務(wù)又需要等syncMainMethod方法執(zhí)行結(jié)束才能執(zhí)行礼仗。而syncMainMethod執(zhí)行到第一個任務(wù)的時候吐咳,又要等第一個任務(wù)執(zhí)行完才能玩下執(zhí)行第二和第三個任務(wù)。簡單來說元践,就是syncMainMethod方法結(jié)束后才能執(zhí)行第一個同步任務(wù)韭脊,而第一個同步任務(wù)又在syncMainMethod方法中,需要執(zhí)行了本任務(wù)之后卢厂,才能繼續(xù)執(zhí)行其他任務(wù)乾蓬,直到syncMainMethod方法完全結(jié)束,相互等待慎恒,造成了死鎖任内。

那么,現(xiàn)在的情況就是第一個任務(wù)都在等對方執(zhí)行完畢融柬,造成了死鎖死嗦,所以我們的任務(wù)就執(zhí)行不了,而且syncMainMethod---end也沒打印

要是如果不在主線程中調(diào)用粒氧,而在其他線程中調(diào)用會如何呢越除?

  • 不會開啟新線程,執(zhí)行完一個任務(wù)外盯,再執(zhí)行下一個任務(wù)(在其他線程中調(diào)用)

OC版本:

    dispatch_queue_t queue = dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        [self syncMainMethod];
    });

輸出結(jié)果:
2017-09-19 14:51:03.723 OC-GCD[4483:161903] syncMainMethod---begin
2017-09-19 14:51:03.723 OC-GCD[4483:161788] 1------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 1------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 2------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 2------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 3------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161788] 3------<NSThread: 0x60800007c500>{number = 1, name = main}
2017-09-19 14:51:03.724 OC-GCD[4483:161903] syncMainMethod---end

Swift版本:

        let queue = DispatchQueue(label: "test.queue", attributes: .concurrent)
        queue.async {
            self.syncMainMethod()
        }

輸出結(jié)果:
syncMainMethod---begin
1------ <NSThread: 0x61800007aa40>{number = 1, name = main}
1------ <NSThread: 0x61800007aa40>{number = 1, name = main}
2------ <NSThread: 0x61800007aa40>{number = 1, name = main}
2------ <NSThread: 0x61800007aa40>{number = 1, name = main}
3------ <NSThread: 0x61800007aa40>{number = 1, name = main}
3------ <NSThread: 0x61800007aa40>{number = 1, name = main}
syncMainMethod---end

  • 在其他線程中使用主隊列 + 同步執(zhí)行可以看到:所有任務(wù)都是在主線程中執(zhí)行的摘盆,并沒有開啟新線程。而且由于主隊列是串行隊列饱苟,可以按照順序一個一個執(zhí)行孩擂。
  • 同時我們還可以看到,所有任務(wù)都在打印的syncConcurrent---beginsyncConcurrent---end之間箱熬,說明任務(wù)是添加到隊列中馬上執(zhí)行的类垦。

6. 主隊列 + 異步執(zhí)行

  • 只有在主線程中執(zhí)行任務(wù)狈邑,執(zhí)行完一個任務(wù),再執(zhí)行下一個任務(wù)

OC版本:

- (void)asyncMainMethod{
    NSLog(@"asyncMainMethod---begin");
    
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"1------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"2------%@",[NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (int i = 0; i < 2; ++i) {
            NSLog(@"3------%@",[NSThread currentThread]);
        }
    });
    
    NSLog(@"asyncMainMethod---end");
}

輸出結(jié)果:
2017-09-19 22:30:10.807 OC-GCD[1151:23348] asyncMainMethod---begin
2017-09-19 22:30:10.808 OC-GCD[1151:23348] asyncMainMethod---end
2017-09-19 22:30:10.809 OC-GCD[1151:23348] 1------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 1------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 2------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 2------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 3------<NSThread: 0x60000006e500>{number = 1, name = main}
2017-09-19 22:30:10.810 OC-GCD[1151:23348] 3------<NSThread: 0x60000006e500>{number = 1, name = main}

Swift版本:

    func asyncMainMethod() {
        
        print("asyncMainMethod---begin")
        
        let queue = DispatchQueue.main
        
        queue.async {
            for _ in 0..<2 {
                print("1------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("2------",Thread.current)
            }
        }
        
        queue.async {
            for _ in 0..<2 {
                print("3------",Thread.current)
            }
        }
        
        print("asyncMainMethod---end")
        
    }

輸出結(jié)果:
asyncMainMethod---begin
asyncMainMethod---end
1------ <NSThread: 0x6080000707c0>{number = 1, name = main}
1------ <NSThread: 0x6080000707c0>{number = 1, name = main}
2------ <NSThread: 0x6080000707c0>{number = 1, name = main}
2------ <NSThread: 0x6080000707c0>{number = 1, name = main}
3------ <NSThread: 0x6080000707c0>{number = 1, name = main}
3------ <NSThread: 0x6080000707c0>{number = 1, name = main}

  • 我們可以發(fā)現(xiàn)所有任務(wù)都在主線程鐘蚤认,雖然是異步執(zhí)行米苹,具備開啟線程的能力,但是因為是主隊列砰琢,所以所有任務(wù)都在主線程中蘸嘶,并且一個接一個執(zhí)行。
  • 另一方面可以看出陪汽,所有任務(wù)是在打印的asyncMainMethod---beginasyncMainMethod---end之后才開始執(zhí)行的亏较。說明任務(wù)不是馬上執(zhí)行,而是將所有任務(wù)添加到隊列之后才開始同步執(zhí)行掩缓。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市遵岩,隨后出現(xiàn)的幾起案子你辣,更是在濱河造成了極大的恐慌,老刑警劉巖尘执,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舍哄,死亡現(xiàn)場離奇詭異,居然都是意外死亡誊锭,警方通過查閱死者的電腦和手機表悬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來丧靡,“玉大人蟆沫,你說我怎么就攤上這事∥轮危” “怎么了饭庞?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長熬荆。 經(jīng)常有香客問我舟山,道長,這世上最難降的妖魔是什么卤恳? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任累盗,我火速辦了婚禮,結(jié)果婚禮上突琳,老公的妹妹穿的比我還像新娘若债。我一直安慰自己,他們只是感情好本今,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布拆座。 她就那樣靜靜地躺著主巍,像睡著了一般。 火紅的嫁衣襯著肌膚如雪挪凑。 梳的紋絲不亂的頭發(fā)上孕索,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音躏碳,去河邊找鬼搞旭。 笑死,一個胖子當(dāng)著我的面吹牛菇绵,可吹牛的內(nèi)容都是我干的肄渗。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼咬最,長吁一口氣:“原來是場噩夢啊……” “哼翎嫡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起永乌,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤惑申,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后翅雏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體圈驼,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年望几,在試婚紗的時候發(fā)現(xiàn)自己被綠了绩脆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡橄抹,死狀恐怖靴迫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情害碾,我是刑警寧澤矢劲,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站慌随,受9級特大地震影響芬沉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阁猜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一丸逸、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧剃袍,春花似錦黄刚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涛救。三九已至,卻和暖如春业扒,著一層夾襖步出監(jiān)牢的瞬間检吆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工程储, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蹭沛,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓章鲤,卻偏偏與公主長得像摊灭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子败徊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 本文首發(fā)于我的個人博客:「程序員充電站」[https://itcharge.cn]文章鏈接:「傳送門」[https...
    ITCharge閱讀 347,898評論 308 1,926
  • macvim配置 最終效果如下: 系統(tǒng)環(huán)境 macos10.12.4 homebrew1.2.1 python3....
    Like_eb56閱讀 69,394評論 5 65
  • 那是變化之下的不變與守望帚呼。 有時候成功的不一定成功,堅持下來的不一定合適皱蹦。那么堅持是否真有其價值萝挤?未來又究竟在何方...
    刀刀筱白閱讀 241評論 0 0
  • 周末,我布置學(xué)生一項小練筆:選取課外書上的2―5個四字詞語來寫一個片段根欧,內(nèi)容不限,寫什么都可以端蛆,只要用上...
    嘎魚嘎魚閱讀 295評論 0 0