多線程:
基礎(chǔ)知識:
進(jìn)程:在系統(tǒng)中正在運(yùn)行的應(yīng)用程序。
每個(gè)進(jìn)程之間是獨(dú)立的,均運(yùn)行在其專用且受保護(hù)的內(nèi)存空間內(nèi)。進(jìn)程之間可以相互通信。
線程:每個(gè)進(jìn)程至少要有一個(gè)線程(線程是用來執(zhí)行任務(wù)的)。一個(gè)進(jìn)程中的所有任務(wù)都在線程中執(zhí)行。
線程的串行:一個(gè)線程中任務(wù)的執(zhí)行是串行的。如果想在一個(gè)線程中執(zhí)行多個(gè)任務(wù),只能一個(gè)一個(gè)按順序執(zhí)行這些任務(wù)。同一時(shí)間內(nèi),一個(gè)線程只能執(zhí)行一個(gè)任務(wù)。
多線程:一個(gè)進(jìn)程中可以開啟多個(gè)線程,每條線程可以并行(同時(shí))執(zhí)行不同的任務(wù)
多線程原理:
同一時(shí)間CPU只能處理一條線程,只有一條線程在工作。
多線程同時(shí)執(zhí)行,其實(shí)是CPU快速的在多條線程之間調(diào)度。如果CPU調(diào)度線程的時(shí)間足夠快,就造成了多線程并發(fā)執(zhí)行的假象。
多線程優(yōu)缺點(diǎn)
優(yōu)點(diǎn):能適當(dāng)提高程序的執(zhí)行效率;能適當(dāng)提高資源的利用率
缺點(diǎn):創(chuàng)建線程是有開銷的,ios下主要成本包括:內(nèi)核數(shù)據(jù)結(jié)構(gòu),??臻g,創(chuàng)建線程大約要90ms的創(chuàng)建時(shí)間;如果開啟大量的線程,會(huì)降低程序的性能;線程越多,CPU在調(diào)度線程上的開銷就越大;程序設(shè)計(jì)更加復(fù)雜:比如線程之間的通信、多線程的數(shù)據(jù)共享。
多線程在IOS開發(fā)中的應(yīng)用:
主線程:一個(gè)IOS程序運(yùn)行后,默認(rèn)會(huì)開啟1條線程,稱為“主線程”或“UI線程”。
主線程作用:顯示/刷新UI界面;處理UI事件(比如點(diǎn)擊事件、滾動(dòng)事件、拖拽事件等)。
耗時(shí)操作放在子線程(后臺(tái)線程、非主線程)。
注意:不要把比較耗時(shí)的操作放在主線程中。
iOS中多線程的實(shí)現(xiàn)方案
1 pthread:同于的多線程,跨平臺(tái),基于c語言,線程的生命周期由程序員管理。使用難度大,使用頻率幾乎不用。
2 NSThread:基于OC語言,生命周期偶爾需要程序員管理(管理創(chuàng)建),偶爾使用。
3 GCD:基于C語言,旨在代替NSThread等線程技術(shù),充分利用設(shè)備的多核,生命周期自動(dòng)管理。
4 NSOperation:基于OC語言,基于GCD,使用更加面向?qū)ο螅菺CD多了一些簡單實(shí)用的功能。經(jīng)常使用。
NSThread :3種創(chuàng)建方式
1. 使用alloc init創(chuàng)建
NSThread*thread =? [[NSThreadalloc]initWithTarget:selfselector:@selector(run:)object:@"rose"];
2.創(chuàng)建線程后自動(dòng)啟動(dòng)線程
[NSThreaddetachNewThreadSelector:@selector(run:)toTarget:selfwithObject:@"jack"];
3.隱式創(chuàng)建并啟動(dòng)線程
[selfperformSelectorInBackground:@selector(run:)withObject:@"Lily"];
多線程的安全隱患:
資源共享:多個(gè)線程可能會(huì)同時(shí)訪問一塊資源
安全隱患解決—互斥鎖
互斥鎖使用格式
@synchronized(鎖對象){需要鎖定的代碼}
注意:鎖定一份代碼只用1把鎖,用多把鎖是無效的
互斥鎖的優(yōu)缺點(diǎn)
優(yōu)點(diǎn):能有效防止因多線程搶奪資源造成的數(shù)據(jù)安全問題
缺點(diǎn):需要消耗大量的CPU資源
互斥鎖使用的前提:多線程搶奪同一塊資源
線程同步:多條線程在同一條線上執(zhí)行(按順序地執(zhí)行任務(wù))
互斥鎖:使用了線程同步技術(shù)
原子和非原子屬性
nonatomic:非原子屬性,不會(huì)加鎖
atomic:原子屬性,為setter方法加鎖(默認(rèn)就是atomic)
IOS開發(fā)的建議:所有屬性都聲明為nonatomic;盡量避免多線程搶奪同一塊資源。盡量將加鎖、資源搶奪的業(yè)務(wù)邏輯交給服務(wù)器。
線程間通信:
一個(gè)進(jìn)程中,線程往往不是孤立存在的,多個(gè)線程之間需要進(jìn)行通信。
線程間通信的體現(xiàn):
1個(gè)線程傳遞數(shù)據(jù)給另一個(gè)線程
在1個(gè)線程中執(zhí)行完特定任務(wù)后,轉(zhuǎn)到另1個(gè)線程繼續(xù)執(zhí)行任務(wù)。
GCD(Grand Central Dispatch):偉大的中樞調(diào)度器。純C語言
GCD優(yōu)勢:是蘋果公司為多核的并行運(yùn)算提出的解決方案;自動(dòng)利用更多的CPU內(nèi)核;會(huì)自動(dòng)管理線程的生命周期。
GCD的2個(gè)核心概念
任務(wù)
隊(duì)列
GCD使用步驟2個(gè):
定制任務(wù)
將任務(wù)添加到隊(duì)列中:GCD會(huì)自動(dòng)將隊(duì)列中的任務(wù)取出,放到對應(yīng)的線程中執(zhí)行;任務(wù)的取出遵循先進(jìn)先出原則。
執(zhí)行任務(wù):GCD中有2個(gè)用來執(zhí)行任務(wù)的常用函數(shù):
同步:dispatch_sync();
異步:dispatch_async();
同步:只能在當(dāng)前線程中執(zhí)行任務(wù),不具備開啟新線程的能力
異步:可以在新的線程中執(zhí)行,具備開啟新線程的能力
隊(duì)列的類型
并發(fā)隊(duì)列(Concurrent Dispatch Queue):多個(gè)任務(wù)并發(fā)執(zhí)行(自動(dòng)開啟好多個(gè)線程執(zhí)行任務(wù)),并發(fā)功能只有在異步的時(shí)候才有效。
串行隊(duì)列(Serial Dispatch Queue):任務(wù)一個(gè)接一個(gè)的執(zhí)行
同步和異步主要影響:是否開啟新的線程
串行和并行主要影響:是任務(wù)的執(zhí)行方式
GCD中還有個(gè)用來執(zhí)行任務(wù)的函數(shù)
dispatch_barrier_async(dispatch_queue_t queue, ^(void)block);
在前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,而且它后面的任務(wù)等它執(zhí)行完成之后才會(huì)執(zhí)行。
這個(gè)queue不能是全局的并發(fā)隊(duì)列
GCD中常用的其他函數(shù)
延遲執(zhí)行:iOS中常見的延時(shí)執(zhí)行
1 調(diào)用NSObject的方法:
[selfperformSelector:@selector(run)withObject:nilafterDelay:2.0];
2使用GCD函數(shù)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,2.0),dispatch_get_main_queue(), ^{
NSLog(@"");
});
3使用Timer
[NSTimerscheduledTimerWithTimeInterval:2.0target:selfselector:@selector(run)userInfo:nilrepeats:YES];
一次性代碼:
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
//默認(rèn)是線程安全的
});
dispatch_once:防止資源重復(fù)加載,但懶加載中不能使用[因?yàn)樗钦麄€(gè)程序運(yùn)行過程中只執(zhí)行一次]
快速迭代遍歷函數(shù)
dispatch_queue_tqueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_apply(10, queue, ^(size_tindex) {
//執(zhí)行10次代碼,index順序不確定
});
隊(duì)列組(group)
要求:首先,分別異步執(zhí)行兩個(gè)耗時(shí)操作;其次,等2個(gè)異步操作都執(zhí)行完畢后,再回到主線程執(zhí)行。 如果想要快速高效的完成上述要求,可以使用隊(duì)列。
dispatch_group_tgroup =dispatch_group_create();
dispatch_group_async(group,dispatch_get_global_queue(0,0), ^{
//執(zhí)行第一個(gè)耗時(shí)操作
});
dispatch_group_async(group,dispatch_get_global_queue(0,0), ^{
//執(zhí)行第二個(gè)耗時(shí)操作
});
dispatch_group_notify(group,dispatch_get_main_queue(), ^{
//等前面的異步操作都執(zhí)行完畢后,回到主線程
});
GCD單例模式
單例模式:保證程序在運(yùn)行中,一個(gè)類只有一個(gè)實(shí)例,而且該實(shí)例易于外界訪問。節(jié)約系統(tǒng)資源。
使用場合:共享資源(這個(gè)資源只創(chuàng)建一次)
普通創(chuàng)建單例模式方法
調(diào)用alloc實(shí)際上會(huì)繼承父類的+(instancetype)allocWithZone:(struct_NSZone*)zone[allocWithZone分配內(nèi)存]
NSOperation:在GCD的繼承上對OC的封裝
作用:配合使用NSOperation和NSOperationQueue 也能夠?qū)崿F(xiàn)多線程編程
步驟:1 將需要的任務(wù)封裝到一個(gè)NSOperation對象中
2 將NSOperation對象添加到NSOperationQueue中
3 系統(tǒng)自動(dòng)將NSOperationQueue中的NSOperation取出來
4? 將取出的NSOperation封裝的任務(wù)放在一條線程中執(zhí)行
NSOperation是個(gè)抽象類,不具備封裝操作的能力,必須使用它的子類
使用NSOperation子類的方式有3種
1 NSInvocationOperation
2 NSBlockOperation
3 自定義子類繼承NSOperation,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法
NSOperationQueue的作用[其任務(wù)是放在自定義類的-(void) main{}函數(shù)中即可]
NSOperation可以調(diào)用start方法來執(zhí)行任務(wù),但默認(rèn)是同步執(zhí)行的
如果將NSOperation添加到NSOperationQueue中則默認(rèn)是異步執(zhí)行的。
注意:/* GCD隊(duì)列類型:串行隊(duì)列[主隊(duì)列/自己創(chuàng)建的]并行隊(duì)列[全局/自己創(chuàng)建的]? */
/* NSOperation的隊(duì)列類型1主隊(duì)列:[NSOperationQueue mainQueue],凡是添加到主隊(duì)了中的NSOperation對象,都會(huì)放到主線程中執(zhí)行。
2其他隊(duì)列(串行、并發(fā)):[[NSOperationQueue alloc]init],添加到這種隊(duì)列中的NSOperation對象都會(huì)自動(dòng)放到子線程中執(zhí)行。
*/
控制線程數(shù)量? :
/*創(chuàng)建隊(duì)列*/
NSOperationQueue*queue = [[NSOperationQueuealloc]init];
/*設(shè)置最大并發(fā)操作數(shù)*/
queue.maxConcurrentOperationCount=x;
//如果最大并發(fā)數(shù)是1,那么就是串行隊(duì)列
掛起隊(duì)列 [暫停執(zhí)行]:
queue.suspend = YES;[NO,恢復(fù)隊(duì)列,繼續(xù)執(zhí)行]
蘋果官方建議:在[queuecancelAllOperations]即取消隊(duì)列的情況下,如果自定義NSOperation;執(zhí)行完一段耗時(shí)操作時(shí)要去判斷任務(wù)是不是被取消 即self.isCancelled。
NSOperation中設(shè)置依賴
/*設(shè)置依賴*/
[operation3addDependency:operation1];
[operation3addDependency:operation2];
operation3放在operation1和operation2執(zhí)行完后執(zhí)行
可以在不同的隊(duì)列中設(shè)置依賴
NSOperation中監(jiān)聽
op5.completionBlock= ^{
NSLog(@"op5執(zhí)行完畢---%@",[NSThreadcurrentThread]);
};
NSOperation線程之間的通信
[[NSOperationQueuemainQueue]addOperationWithBlock:^{
//回到主線程中執(zhí)行
}];
在NSOpeation中合并圖片,[等待圖一和圖二下載好在合成]可以使用依賴
多圖片下載
可以使用第三方框架:SDWebImage
[cell.imageViewsd_setImageWithURL:[NSURLURLWithString:app.icon]placeholderImage:[UIImageimageNamed:@"aa"]];