來(lái)來(lái)來(lái)!讓我們一同回顧一下多線程的使用

iOS中目前有4套多線程方案,分別是

Pthreads

NSThread

GCD

NSOperation & NSOperationQueue

提到多線程,毫無(wú)疑問(wèn)都能回答出這四種!

今天我們主要回顧一下我們最熟悉!最常用的“GCD”;

二.GCD

GCD 完整字段為Grand Centeral Dispatch,是蘋果為多核的并行運(yùn)算提出的解決方案,所以會(huì)自動(dòng)合理地利用更多的CPU內(nèi)核(比如雙核、四核),最重要的是它會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程),完全不需要我們管理,我們只需要告訴該干什么就行。GCD使用的是C語(yǔ)言,不過(guò)由于使用了Block,使用起來(lái)更加方便靈活,目前基本大家都使用GCD解決多線程問(wèn)題。

GCD的優(yōu)勢(shì)

GCD是蘋果為多核的并行運(yùn)算提出的解決方案

GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核

GCD會(huì)自動(dòng)管理線程的生命周期創(chuàng)建線程調(diào)度任務(wù)``銷毀線程

程序員只需要告訴GCD想要執(zhí)行什么任務(wù),不需要管理任何線程管理代碼

三.任務(wù)和隊(duì)列

在GCD中,加入了兩個(gè)非常重要的概念:任務(wù)和隊(duì)列

任務(wù):即你想要進(jìn)行的操作,比如說(shuō)網(wǎng)絡(luò)請(qǐng)求,數(shù)據(jù)緩存等,在GCD中就是一個(gè)Block,所以添加任務(wù)十分方便。任務(wù)有兩種執(zhí)行方式:同步執(zhí)行和異步執(zhí)行,他們之間的區(qū)別是 是否會(huì)創(chuàng)建新的線程

同步(sync)操作:會(huì)阻塞當(dāng)前線程并等待Block中的任務(wù)執(zhí)行完畢,然后當(dāng)前線程才會(huì)繼續(xù)往下運(yùn)行

異步(async)操作:當(dāng)前線程會(huì)直接往下執(zhí)行,不會(huì)阻塞當(dāng)前線程

同步(sync)和異步(async)的主要區(qū)別在于會(huì)不會(huì)阻塞當(dāng)前線程,直到Block中的任務(wù)執(zhí)行完畢

隊(duì)列:用于存放任務(wù),一共有兩種隊(duì)列

串行隊(duì)列中的任務(wù)會(huì)根據(jù)隊(duì)列的定義FIFO的執(zhí)行,一個(gè)接一個(gè)的,先進(jìn)先出的執(zhí)行

放到串行隊(duì)列的任務(wù),GCD會(huì)FIFO(先進(jìn)先出)地取出來(lái)一個(gè),執(zhí)行一個(gè),然后取下一個(gè),這樣一個(gè)一個(gè)的執(zhí)行。

放到并行隊(duì)列的任務(wù),GCD也會(huì)FIFO的取出來(lái),但不同的是,它取出來(lái)一個(gè)就會(huì)放到別的線程,然后再取出來(lái)一個(gè)又放到另一個(gè)的線程,這樣由于取的動(dòng)作很快,忽略不計(jì),看起來(lái),所以的任務(wù)都是一起執(zhí)行的,不過(guò)需要注意,GCD會(huì)根據(jù)系統(tǒng)資源控制并行的數(shù)量,所以如果任務(wù)很多,它并不會(huì)讓所有任務(wù)同時(shí)執(zhí)行。

同步執(zhí)行異步執(zhí)行

串行隊(duì)列當(dāng)前線程,一個(gè)一個(gè)執(zhí)行其他線程,一個(gè)一個(gè)執(zhí)行

并行隊(duì)列當(dāng)前線程,一個(gè)一個(gè)執(zhí)行開很多線程,一起執(zhí)行

四.創(chuàng)建隊(duì)列

主隊(duì)列:這是一個(gè)特殊的串行隊(duì)列,用于刷新UI,任何需要刷新UI的工作都要在主隊(duì)列執(zhí)行,所以一般耗時(shí)的任務(wù)都要放到別的線程執(zhí)行

//Objective-C

dispatch_queue_t queue = dispatch_get_main_queue();

//Swift

let queue = DispatchQueue.main

自己創(chuàng)建的隊(duì)列:第一個(gè)參數(shù)是標(biāo)識(shí)符,用于Debug的時(shí)候標(biāo)識(shí)唯一的隊(duì)列,可以為空。具體可以查看Xcode的文檔查看參數(shù)意義

自己可以創(chuàng)建串行隊(duì)列,也可以創(chuàng)建并行隊(duì)列,它有兩個(gè)參數(shù),第一個(gè)上面已經(jīng)說(shuō)了,第二個(gè)參數(shù)用了表示創(chuàng)建的隊(duì)列是串行的還是并行的,傳入DISPATCH_QUEUE_SERIAL或NULL標(biāo)示創(chuàng)建串行隊(duì)列,傳入DISPATCH_QUEUE_CONCURRENT表示創(chuàng)建并行隊(duì)列

//Objective-C

//串行隊(duì)列

dispatch_queue_t serialQueue = dispatch_queue_create("serial1", NULL);

dispatch_queue_t seqialQueue = dispatch_queue_create("serial2", DISPATCH_QUEUE_SERIAL);

//并行隊(duì)列

dispatch_queue_t concurrentQueue = dispatch_queue_create("concurrent", DISPATCH_QUEUE_CONCURRENT);

//Swift

//主隊(duì)列(串行)

let queue = DispatchQueue.main

全局并行隊(duì)列:只要是并行任務(wù)一般都加入到這個(gè)隊(duì)列。這是系統(tǒng)提供的一個(gè)并發(fā)隊(duì)列

//全局并發(fā)隊(duì)列

//Objective-C

dispatch_queue_t globeQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//Swift

let serialQueue = DispatchQueue.global()

五.創(chuàng)建任務(wù)

同步任務(wù):會(huì)阻塞當(dāng)前線程(SYNC)

Objective-C

//同步任務(wù)

dispatch_sync(serialQueue, ^{

NSLog(@"%@",[NSThread currentThread]);

});

異步任務(wù):不會(huì)阻塞當(dāng)前線程(ASYNC)

Objective-C

//異步任務(wù)

dispatch_sync(serialQueue, ^{

NSLog(@"%@",[NSThread currentThread]);

});

示例一:

以下代碼在主線程調(diào)用,結(jié)果是什么?

NSLog(@"before - %@",[NSThread currentThread]);

dispatch_sync(dispatch_get_main_queue(), ^{

NSLog(@"sync- %@",[NSThread currentThread]);

});

NSLog(@"after - %@",[NSThread currentThread]);

答案:只會(huì)打印第一句:before - {number = 1, name = main},然后主線程就卡死,程序奔潰

解釋:同步任務(wù)會(huì)阻塞當(dāng)前線程,然后把Block中的任務(wù)放到指定的隊(duì)列中執(zhí)行,只有等到Block中的任務(wù)完成后才會(huì)讓線程繼續(xù)往下運(yùn)行。

那么這里的步驟就是:打印完第一句后,dispatch_sync立即阻塞當(dāng)前的主線程,然后把Block中的任務(wù)放到main_queue,可是main_queue中的任務(wù)會(huì)被取出來(lái)放到主線程中執(zhí)行,但主線程這個(gè)時(shí)候已經(jīng)被阻塞了,所以Block中的任務(wù)就不能完成,它不完成,dispatch_sync就會(huì)一直阻塞主線程,這就是死鎖現(xiàn)象,導(dǎo)致主線程一直卡死

示例二

以下代碼會(huì)產(chǎn)生什么結(jié)果?

dispatch_queue_t serialQueue = dispatch_queue_create("serial1", NULL);

NSLog(@"begain - %@",[NSThread currentThread]);

dispatch_async(serialQueue, ^{

NSLog(@"beforeSync: %@",[NSThread currentThread]);

dispatch_sync(serialQueue, ^{

NSLog(@"sync-: %@",[NSThread currentThread]);

});

NSLog(@" afterSync-: %@",[NSThread currentThread]);

});

NSLog(@"last-: %@",[NSThread currentThread]);

}

答案:

2017-03-20 16:59:11.436 TestGcd[8245:264276] begain - {number = 1, name = main}

2017-03-20 16:59:11.438 TestGcd[8245:264276] last: {number = 1, name = main}

2017-03-20 16:59:11.438 TestGcd[8245:264329] beforeSync: {number = 3, name = (null)}

(lldb)

很明顯sync-: %@和afterSync-: %@沒(méi)有打印出來(lái),這是為什么?我們來(lái)一步步分析一下:

分析:

使用DISPATCH_QUEUE_SERIAL這個(gè)參數(shù),創(chuàng)建一個(gè)串行隊(duì)列

打印begain - %@這句

dispatch_async異步執(zhí)行,所以當(dāng)前線程不會(huì)阻塞,于是有了2條線程,一條當(dāng)前線程繼續(xù)往下打印出last-: %@這句,另一條執(zhí)行Block中的內(nèi)容打印beforeSync: %@這句,因?yàn)檫@兩條線程是并行的,所以打印的先后順序無(wú)所謂

注意,高潮來(lái)了…現(xiàn)在的情況和上個(gè)例子一樣,dispatch_sync同步執(zhí)行,于是它所在的線程會(huì)被阻塞,一直等到sync里的任務(wù)執(zhí)行完才會(huì)繼續(xù)往下。于是sync就高興的把自己Block中的任務(wù)放到serialQueue中,可誰(shuí)想serialQueue是一個(gè)串行隊(duì)列,一次執(zhí)行一個(gè)任務(wù),所以sync的Block必須等到前一個(gè)任務(wù)執(zhí)行完畢,可萬(wàn)萬(wàn)沒(méi)想到的是serialQueue正在執(zhí)行的任務(wù)就是被sync阻塞了的那個(gè),于是又發(fā)生了死鎖,所以sync所在的線程被卡死了,剩下的兩句代碼自然不會(huì)打印。

六.隊(duì)列組

隊(duì)列組可以將很多隊(duì)列添加到一個(gè)組里,這樣做的好處是,當(dāng)這個(gè)組里所有的任務(wù)都執(zhí)行完了,隊(duì)列組會(huì)通過(guò)一個(gè)方法通知我們。下面是使用方法,這是一個(gè)很實(shí)用的功能

//1.創(chuàng)建隊(duì)列組

dispatch_group_t group = dispatch_group_create();

//2.創(chuàng)建隊(duì)列

dispatch_queue_t queueGroup = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

//3.多次使用隊(duì)列組的方法執(zhí)行任務(wù),只有異步方法

//3.1。執(zhí)行3次循環(huán)

dispatch_group_async(group, queueGroup, ^{

for (NSUInteger i = 0; i < 3; i++) {

NSLog(@"group - 01 - %@",[NSThread currentThread]);

}

});

//3.2。主隊(duì)列執(zhí)行8次循環(huán)

dispatch_group_async(group, dispatch_get_main_queue(), ^{

for (NSInteger i = 0; i < 8; i++) {

NSLog(@"group - 02 - %@",[NSThread currentThread]);

}

});

//3.3.執(zhí)行5次循環(huán)

dispatch_group_async(group, queueGroup, ^{

for (NSUInteger i = 0; i < 5; i++) {

NSLog(@"group - 03 - %@", [ NSThread currentThread]);

}

});

//4.都完成后會(huì)自動(dòng)通知

dispatch_group_notify(group, dispatch_get_main_queue(), ^{

NSLog(@"完成 - %@",[NSThread currentThread]);

});

打印結(jié)果

2017-03-20 17:43:17.266 TestGcd[9020:294003] group - 01 - {number = 3, name = (null)}

2017-03-20 17:43:17.266 TestGcd[9020:294005] group - 03 - {number = 4, name = (null)}

2017-03-20 17:43:17.267 TestGcd[9020:294003] group - 01 - {number = 3, name = (null)}

2017-03-20 17:43:17.267 TestGcd[9020:294005] group - 03 - {number = 4, name = (null)}

2017-03-20 17:43:17.268 TestGcd[9020:294003] group - 01 - {number = 3, name = (null)}

2017-03-20 17:43:17.269 TestGcd[9020:294005] group - 03 - {number = 4, name = (null)}

2017-03-20 17:43:17.272 TestGcd[9020:294005] group - 03 - {number = 4, name = (null)}

2017-03-20 17:43:17.272 TestGcd[9020:294005] group - 03 - {number = 4, name = (null)}

2017-03-20 17:43:17.280 TestGcd[9020:293944] group - 02 - {number = 1, name = main}

2017-03-20 17:43:17.281 TestGcd[9020:293944] group - 02 - {number = 1, name = main}

2017-03-20 17:43:17.284 TestGcd[9020:293944] group - 02 - {number = 1, name = main}

2017-03-20 17:43:17.285 TestGcd[9020:293944] group - 02 - {number = 1, name = main}

2017-03-20 17:43:17.286 TestGcd[9020:293944] group - 02 - {number = 1, name = main}

2017-03-20 17:43:17.294 TestGcd[9020:293944] group - 02 - {number = 1, name = main}

2017-03-20 17:43:17.312 TestGcd[9020:293944] group - 02 - {number = 1, name = main}

2017-03-20 17:43:17.312 TestGcd[9020:293944] group - 02 - {number = 1, name = main}

2017-03-20 17:43:17.315 TestGcd[9020:293944] 完成 - {number = 1, name = main}

以上就是GCD的基本功能,但它的能力遠(yuǎn)不止這寫些,之后我會(huì)更新它的其它用途? 有寶貴意見歡迎糾正!??!

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

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

  • 文章目錄GCD簡(jiǎn)介任務(wù)和隊(duì)列GCD的使用步驟隊(duì)列的創(chuàng)建方法任務(wù)的創(chuàng)建方法GCD的基本使用并行隊(duì)列 + 同步執(zhí)行并行...
    lusen_b閱讀 298評(píng)論 0 1
  • 在這篇文章中,我將為你整理一下 iOS 開發(fā)中幾種多線程方案,以及其使用方法和注意事項(xiàng)。當(dāng)然也會(huì)給出幾種多線程的案...
    張戰(zhàn)威ican閱讀 699評(píng)論 0 0
  • 一、前言 上一篇文章iOS多線程淺匯-原理篇中整理了一些有關(guān)多線程的基本概念。本篇博文介紹的是iOS中常用的幾個(gè)多...
    nuclear閱讀 2,152評(píng)論 6 18
  • 1. GCD簡(jiǎn)介 什么是GCD呢?我們先來(lái)看看百度百科的解釋簡(jiǎn)單了解下概念 引自百度百科:Grand Centra...
    千尋_544f閱讀 518評(píng)論 0 0
  • 一、前言 本篇博文介紹的是iOS中常用的幾個(gè)多線程技術(shù): NSThread GCD NSOperation 由于a...
    和玨貓閱讀 659評(píng)論 0 1

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