網(wǎng)絡(luò)上關(guān)于多線程的原理和用法的解釋,隨便一搜一大堆,但是那個寬泛過于學(xué)術(shù)性的解釋,我看著太費(fèi)力了。
我就用自己比較容易理解的白話來記錄一下我學(xué)到的知識吧。
一、進(jìn)程
在移動端,一個app就是一個進(jìn)程,在內(nèi)存中占用一定的空間。
在計算機(jī)里,一個程序就是一個進(jìn)程,同樣也占用內(nèi)存空間。
iOS同一時間點(diǎn)只有一個進(jìn)程在使用CPU,只是系統(tǒng)把這個時間片分割地非常短,造成一種多個進(jìn)程同時在執(zhí)行的假象。
二、線程
一個進(jìn)程的執(zhí)行,必然從一個主線程開始。
整個應(yīng)用可以由單個主線程運(yùn)行,但是涉及到一些耗時的任務(wù),例如打開淘寶app,必然要加載一大堆的圖片。
這時,如果只有單線程執(zhí)行,程序必須等著圖片都加載完畢才能繼續(xù)往下執(zhí)行,期間用戶的交互就不起作用,這樣用戶體驗很不好。
所以,這時就衍生出多線程的概念,可以開子線程給那些耗時的任務(wù),在旁邊默默地執(zhí)行,而不影響應(yīng)用的大局。
主線程,一般用來處理主體的展示(例如控制器的切換)和交互事件。
子線程,一般用來處理耗時的任務(wù)。
當(dāng)然,并不是線程越多越好,多線程的使用也是要慎重考慮。
三、同步和異步
我之前一直對同步和異步這個概念理解不清,常常混淆。同步是線程安全呢,還是異步線程安全呢?
今天終于記清楚了這個概念,只要記住一句話——同步,就是同類;異步,就是異類。
已經(jīng)是同類,那肯定是處于同一個線程;異類,那就說明不是一個線程。
四、并行和串行
并行:并發(fā)執(zhí)行
串行:按順序執(zhí)行,一個接一個
五、三種常用創(chuàng)建多線程方式
1、NSThread:程序員手動管理線程,而多線程的情況下,線程什么時候執(zhí)行完畢是未知的,如果管理不好,會造成內(nèi)存泄露,所以這種方法不提倡。
2 、NSOperation/NSOperationQueue。這兩個類必須是搭配使用的,將操作放入操作隊列中,依次執(zhí)行。
1>使用步驟:
* 創(chuàng)建NSOperation
* 添加NSOperation到NSOperationQueue
2>優(yōu)點(diǎn):
* 更加面向?qū)ο?/p>
* 可以控制最大并發(fā)數(shù) maxConcurrentOperationCount,使用這個屬性可以保證同一時間內(nèi)最大的并發(fā)數(shù)
* 添加任務(wù)(Operation)之間的依賴 addDependency,使用這個屬性可以控制一個Operation必須在其依賴的Operation執(zhí)行完畢后才調(diào)用
//1.首先聲明一個全局變量NSOperationQueue *_queue;//2.定義變量_queue = [[NSOperationQueue alloc] init];// 控制最大并發(fā)數(shù):2_queue.maxConcurrentOperationCount = 2;//3.具體某個方法開啟多線程N(yùn)SOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"下載圖片-%@", [NSThread currentThread]);}]; NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"濾鏡處理-%@", [NSThread currentThread]);}]; // op1依賴于op(op執(zhí)行完,才能執(zhí)行op1)[op1 addDependency:op];//操作加入隊列[_queue addOperation:op];[_queue addOperation:op1];
3、GCD(官方推薦使用,純C語言)
調(diào)用同步(異步)執(zhí)行的方法,傳入要并行(串行)執(zhí)行的隊列參數(shù),執(zhí)行方法內(nèi)的block代碼。
說白了就是同一時間有一個還是多個線程執(zhí)行,就看調(diào)用的方法和傳入的隊列類型。
1> 隊列類型
* 全局隊列
* 所有添加到全局隊列中的任務(wù)都是并發(fā)執(zhí)行(同時執(zhí)行,可能會開啟多個線程)
* dispatch_get_global_queue
* 串行隊列
* 所有添加到串行隊列中的任務(wù)都是按順序執(zhí)行(開一條線程)
* dispatch_queue_create("myqueue", 0);
* 主隊列
* 所有添加到主隊列中的任務(wù)都是在主線程中執(zhí)行的(跟方法名沒有關(guān)系)
* dispatch_get_main_queue
2> 同步還是異步,取決于方法名(不影響主隊列,影響全局隊列、串行隊列)
* 同步:dispatch_sync,在當(dāng)前線程執(zhí)行任務(wù),不會開啟新的線程
* 異步:dispatch_async,在其他線程執(zhí)行任務(wù),會開啟新的線程
3>代碼demo演示:
從組合學(xué)上說,總是共有四種情況:串行-同步、串行-異步、并行-同步、并行-異步。
串行-同步:顯然一直只有一個線程在執(zhí)行(這個就是真正意義上單線程)
串行-異步:可能會產(chǎn)生多個線程,但是同一時間只有一個線程在執(zhí)行(異步雖然會產(chǎn)生多個不同線程,但是同一時間只有一個線程在執(zhí)行)
并行-同步:同一時間點(diǎn)有多個相同的線程在執(zhí)行
并行-異步:同一時間有多個不同的線程在執(zhí)行(這是真正意義上的多線程)
下面就只舉兩個例子,剩下的2種情況舉一反三就是了
//串行隊列,執(zhí)行同步方法。說明只有一個線程在執(zhí)行dispatch_queue_t queue = dispatch_queue_create("myqueue", 0);dispatch_sync(queue, ^{ // 耗時操作 NSLog(@"dispatch_async-%@", [NSThread currentThread]);});
//并行隊列,異步執(zhí)行。說明同一時間多個線程一起執(zhí)行dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);dispatch_sync(queue, ^{ // 耗時操作 NSLog(@"dispatch_async-%@", [NSThread currentThread]);});
而主隊列的使用,常常用來執(zhí)行完子線程后,要講數(shù)據(jù)返回主線程來進(jìn)行處理。
比如開啟子線程下載某個資源,下載完畢需要回調(diào)到主線程來展示。
可以在子線程完成的時候調(diào)用以下的方法返回主線程,同時能夠?qū)⒆泳€程得到的參數(shù)傳給處理的selector方法里執(zhí)行。
[xxx performSelectorOnMainThread:@selector(xxx:) withObject:xxx waitUntilDone:YES]
4、開啟后臺線程
[self performSelectorInBackground:@selector(test) withObject:nil]
六、總結(jié)
多線程是很重要的點(diǎn),這些只是我目前掌握的理解,可能有很多不足和理解偏差,以后慢慢改進(jìn),繼續(xù)補(bǔ)充。
新聞熱點(diǎn)
疑難解答