一.概念
1.進(jìn)程
1.進(jìn)程是一個(gè)具有一定獨(dú)立功能的程序關(guān)于某次數(shù)據(jù)集合的一次運(yùn)行活動(dòng)刊咳,它是操作系統(tǒng)分配資源的基本單元.
2.進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序蛛勉,就是一段程序的執(zhí)行過程,我們可以簡(jiǎn)單理解為手機(jī)程序上的一個(gè)app.
3.進(jìn)程只有一個(gè)。
2.線程
1.程序執(zhí)行流的最小單元蔬捷,線程是進(jìn)程中的一個(gè)實(shí)體.2.一個(gè)進(jìn)程要想執(zhí)行任務(wù),必須要有線程,至少有一條線程.其實(shí)應(yīng)用程序啟動(dòng)的時(shí)候我們的系統(tǒng)就會(huì)默認(rèn)幫我們的應(yīng)用程序開啟一條線程,這條線程也叫做'主線程',或者'UI線程'
3.進(jìn)程和線程的關(guān)系
1.線程是進(jìn)程的執(zhí)行單元垄提,進(jìn)程的所有任務(wù)都在線程中執(zhí)行!
2.線程是 CPU 調(diào)用的最小單位
3.進(jìn)程是 CPU 分配資源和調(diào)度的單位
4.一個(gè)程序可以對(duì)應(yīng)過個(gè)進(jìn)程,一個(gè)進(jìn)程中可有多個(gè)線程,但至少要有一條線程
5.同一個(gè)進(jìn)程內(nèi)的線程共享進(jìn)程資源
4.同步
只能在當(dāng)前線程按先后順序依次執(zhí)行周拐,不開啟新線程铡俐。
5.異步
可以在當(dāng)前線程開啟多個(gè)新線程執(zhí)行,可不按順序執(zhí)行妥粟。
6.隊(duì)列
裝載線程任務(wù)的隊(duì)形結(jié)構(gòu)审丘。
7.并發(fā)
線程執(zhí)行可以同時(shí)一起進(jìn)行執(zhí)行。
8.串行
線程執(zhí)行只能依次逐一先后有序的執(zhí)行勾给。
二.ios多線程對(duì)比
NSThread
每個(gè)NSThread對(duì)象對(duì)應(yīng)一個(gè)線程滩报,真正最原始的線程。1.優(yōu)點(diǎn):NSThread輕量級(jí)最低播急,相對(duì)簡(jiǎn)單脓钾。2.缺點(diǎn):手動(dòng)管理所有的線程活動(dòng),如生命周期桩警、線程同步可训、睡眠等。
NSOperation
自帶線程管理的抽象類捶枢。1.優(yōu)點(diǎn):自帶線程周期管理握截,操作上可更注重自己邏輯。2.缺點(diǎn):面向?qū)ο蟮某橄箢惱檬澹荒軐?shí)現(xiàn)它或者使用它定義好的兩個(gè)子類:NSInvocationOperation和NSBlockOperation谨胞。
GCD
Grand Central Dispatch (GCD)是Apple開發(fā)的一個(gè)多核編程的解決方法。
1.優(yōu)點(diǎn):最高效蒜鸡,避開并發(fā)陷阱胯努。
2.缺點(diǎn):基于C實(shí)現(xiàn)。
選擇小結(jié)
1.簡(jiǎn)單而安全的選擇NSOperation實(shí)現(xiàn)多線程即可逢防。2.處理大量并發(fā)數(shù)據(jù)康聂,又追求性能效率的選擇GCD。3.NSThread本人選擇基本上是在做些小測(cè)試上使用胞四,當(dāng)然也可以基于此造個(gè)輪子恬汁。
四.使用方法
1.NSThread
//動(dòng)態(tài)創(chuàng)建線程
-(void)dynamicCreateThread{
? ? NSThread*thread = [[NSThread alloc] initWithTarget:selfselector:@selector(loadImageSource:) object:imgUrl];
? ? thread.threadPriority = 1;// 設(shè)置線程的優(yōu)先級(jí)(0.0 - 1.0,1.0最高級(jí))
? ? [threadstart];
}
//靜態(tài)創(chuàng)建線程
-(void)staticCreateThread{
? ? [NSThread detachNewThreadSelector:@selector(loadImageSource:) toTarget:selfwithObject:imgUrl];
}
//隱式創(chuàng)建線程
-(void)implicitCreateThread{
? ? [selfperformSelectorInBackground:@selector(loadImageSource:) withObject:imgUrl];
}
-(void)loadImageSource:(NSString*)url{
? ? NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
? ? UIImage*image = [UIImageimageWithData:imgData];
? ? if(imgData!=nil) {
? ? ? ? [self performSelectorOnMainThread:@selector(refreshImageView:) withObject:image waitUntilDone:YES];
? ? }else{
? ? ? ? NSLog(@"there no image data");
? ? }
}
-(void)refreshImageView:(UIImage*)image{
? ? [self.imageView setImage:image];
}
補(bǔ)充知識(shí)點(diǎn)
NSThread *current = [NSThread currentThread];? //獲取當(dāng)前線程
NSThread*main = [NSThreadmainThread];? ? //獲取主線程
[NSThread sleepForTimeInterval:2];? //暫停等待線程辜伟,也就是我們通常所說的延遲執(zhí)行2秒
//在指定線程上執(zhí)行操作
[selfperformSelector:@selector(run) onThread:thread withObject:nilwaitUntilDone:YES];
//在主線程上執(zhí)行操作
[selfperformSelectorOnMainThread:@selector(run) withObject:nilwaitUntilDone:YES];
//在當(dāng)前線程執(zhí)行操作
[selfperformSelector:@selector(run) withObject:nil];
2.NSOperation
主要的實(shí)現(xiàn)方式:結(jié)合NSOperation和NSOperationQueue實(shí)現(xiàn)多線程編程氓侧。
1.實(shí)例化NSOperation的子類,綁定執(zhí)行的操作导狡。2.創(chuàng)建NSOperationQueue隊(duì)列约巷,將NSOperation實(shí)例添加進(jìn)來。3.系統(tǒng)會(huì)自動(dòng)將NSOperationQueue隊(duì)列中檢測(cè)取出和執(zhí)行NSOperation的操作
//使用子類NSInvocationOperation3.GCD
-(void)useInvocationOperation{
? ? NSInvocationOperation*invocationOperation = [[NSInvocationOperation alloc] initWithTarget:selfselector:@selector(loadImageSource:) object:imgUrl];
? ? //[invocationOperation start];//直接會(huì)在當(dāng)前線程主線程執(zhí)行
? ? NSOperationQueue *queue = [[NSOperationQueue alloc]init];
? ? [queue addOperation:invocationOperation];
}
//使用子類NSBlockOperation
-(void)useBlockOperation{
? ? NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
? ? ? ? [selfloadImageSource:imgUrl];
? ? }];
? ? NSBlockOperation *blockOperation1 = [NSBlockOperation blockOperationWithBlock:^{
? ? ? ? // 代碼操作1
? ? }];
? ? NSBlockOperation *blockOperation2 = [NSBlockOperation blockOperationWithBlock:^{
? ? ? ? // 代碼操作2
? ? }];
? ? NSBlockOperation *blockOperation3 = [NSBlockOperation blockOperationWithBlock:^{
? ? ? ? // 代碼操作3
? ? }];
? ? /*
?? ? // 添加操作之間的依賴關(guān)系旱捧,所謂“依賴”關(guān)系独郎,就是等待前一個(gè)任務(wù)完成后踩麦,后一個(gè)任務(wù)才能啟動(dòng)
?? ? // 依賴關(guān)系可以跨線程隊(duì)列實(shí)現(xiàn)
?? ? // 提示:在指定依賴關(guān)系時(shí),注意不要循環(huán)依賴氓癌,否則不工作谓谦。
?? ? */
? ? [blockOperation1addDependency:blockOperation];
? ? [blockOperation2addDependency:blockOperation1];
? ? [blockOperation3addDependency:blockOperation2];
? ? NSOperationQueue *queue = [[NSOperationQueue alloc]init];
? ? [queueaddOperation:blockOperation];
? ? [queueaddOperation:blockOperation1];
? ? [queueaddOperation:blockOperation2];
? ? [queueaddOperation:blockOperation3];
? ? [queuesetMaxConcurrentOperationCount:2];// 控制同時(shí)最大并發(fā)的線程數(shù)量
}
//使用繼承NSOperation
-(void)useSubclassOperation{
? ? LoadImageOperation *imageOperation = [LoadImageOperation new];
? ? imageOperation.loadDelegate =self;// 設(shè)置代理
? ? imageOperation.imgUrl = imgUrl;
? ? NSOperationQueue *queue = [[NSOperationQueue alloc]init];
? ? [queue addOperation:imageOperation];
}
-(void)loadImageSource:(NSString*)url{
? ? NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
? ? UIImage*image = [UIImageimageWithData:imgData];
? ? if(imgData!=nil) {
? ? ? ? [self performSelectorOnMainThread:@selector(refreshImageView1:) withObject:image waitUntilDone:YES]; // 在主線程中刷新圖片
? ? }else{
? ? ? ? NSLog(@"there no image data");
? ? }
}
GCD,它是蘋果為多核的并行運(yùn)算提出的解決方案,所以會(huì)自動(dòng)合理地利用更多的CPU內(nèi)核(比如雙核贪婉、四核)反粥,最重要的是它會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)疲迂、銷毀線程)才顿,完全不需要我們管理,我們只需要告訴干什么就行尤蒿。
GCD的基本常用使用方法郑气。
//后臺(tái)執(zhí)行(通常意義的理解為開分線程)
-(void)globalQueue{
? ? dispatch_async(dispatch_get_global_queue(0, 0), ^{
? ? ? ? [selfloadImageSource:imgUrl1];
? ? });
}
//UI線程(通常說的主線程)執(zhí)行(只是為了測(cè)試,長(zhǎng)時(shí)間的加載不能放在主線程)
-(void)mainQueue{
? ? dispatch_async(dispatch_get_main_queue(), ^{
? ? ? ? [selfloadImageSource:imgUrl1];
? ? });
}
//一次性執(zhí)行(常用來寫單例,程序執(zhí)行該代碼部分只會(huì)被創(chuàng)建一次)
-(void)dispatchOnce{
? ? staticdispatch_once_tonceToken;
? ? dispatch_once(&onceToken, ^{
? ? ? ? [selfloadImageSource:imgUrl1];
? ? });
}
//并發(fā)地執(zhí)行循環(huán)迭代腰池,該方法根據(jù)程序運(yùn)行竣贪,不指定在主線程或分線程中
-(void)dispatchApply{
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? size_tcount =10;
? ? dispatch_apply(count, queue, ^(size_ti) {
? ? ? ? NSLog(@"是否為主線程 =====%d",[NSThreadisMainThread]);
? ? ? ? NSLog(@"循環(huán)執(zhí)行第%li次",i);
? ? ? ? //[self loadImageSource:imgUrl1];
? ? });
}
//后臺(tái)執(zhí)行:加載兩張圖片
-(void)globalQueue2{
? ? dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
? ? ? ? UIImage*image1 = [selfloadImage:imgUrl1];
? ? ? ? UIImage*image2 = [selfloadImage:imgUrl2];
? ? ? ? dispatch_async(dispatch_get_main_queue(), ^{
? ? ? ? ? ? self.imageview1.image = image1;
? ? ? ? ? ? self.imageView2.image = image2;
? ? ? ? });
? ? });
}
//并發(fā)線程組
/*
?dispatch_group_t監(jiān)聽這個(gè)調(diào)度組里面的線程,然后等調(diào)度組里面的線程都完成之后巩螃,才會(huì)掉用dispatch_group_notify 更新UI演怎。
?讓后臺(tái)兩個(gè)線程并行執(zhí)行,然后等兩個(gè)線程都結(jié)束后避乏,再匯總執(zhí)行結(jié)果爷耀。
?*/
-(void)dispatchGroup{
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? dispatch_async(queue, ^{
? ? ? ? dispatch_group_t group = dispatch_group_create();
? ? ? ? __blockUIImage*image1 =nil;
? ? ? ? __blockUIImage*image2 =nil;
? ? ? ? dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
? ? ? ? ? ? image1 = [selfloadImage:imgUrl1];
? ? ? ? });
? ? ? ? dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
? ? ? ? ? ? image2 = [selfloadImage:imgUrl2];
? ? ? ? });
? ? ? ? dispatch_group_notify(group, dispatch_get_main_queue(), ^{
? ? ? ? ? ? // 匯總結(jié)果
? ? ? ? ? ? self.imageview1.image = image1;
? ? ? ? ? ? self.imageView2.image = image2;
? ? ? ? });
? ? });
}
// 延遲執(zhí)行
-(void)dispatchAfter{
? ? NSLog(@"Delay 2 seconds");
? ? doubledelayInSeconds =2.0;
? ? dispatch_time_tpopTime =dispatch_time(DISPATCH_TIME_NOW, delayInSeconds *NSEC_PER_SEC);
? ? dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
? ? ? ? [selfloadImageSource:imgUrl1];
? ? });
}
// 自定義dispatch_queue_t 處于分線程中
-(void)defineDispatch{
? ? dispatch_queue_turls_queue =dispatch_queue_create("minggo.app.com",NULL);
? ? dispatch_async(urls_queue, ^{
? ? ? ? NSLog(@"---是否為主線程-%d",[NSThreadisMainThread]);
? ? ? ? [selfloadImageSource:imgUrl1];
? ? });
}
-(void)loadImageSource:(NSString*)url{
? ? NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
? ? UIImage*image = [UIImageimageWithData:imgData];
? ? if(imgData!=nil) {
? ? ? ? [self performSelectorOnMainThread:@selector(refreshImageView1:) withObject:image waitUntilDone:YES];
? ? }else{
? ? ? ? NSLog(@"there no image data");
? ? }
}
//異步緩存圖片完成執(zhí)行操作
- (void)viewDidLoad {
? ? [super viewDidLoad];
? ? // Do any additional setup after loading the view.
? ? //異步緩存圖片完成執(zhí)行操作
? ? [selftest];
}
- (void)test{
? ? dispatch_group_t group = dispatch_group_create();
? ? NSArray*imageArray = [selfgetImageUrl];
? ? for(inti=0;i
? ? ? ? //進(jìn)入組
? ? ? ? dispatch_group_enter(group);
? ? ? ? [[SDWebImageManager sharedManager].imageDownloader downloadImageWithURL:[NSURL URLWithString:imageArray[i]] options:SDWebImageDownloaderLowPriority progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) {
? ? ? ? }completed:^(UIImage*_Nullableimage,NSData*_Nullabledata,NSError*_Nullableerror,BOOLfinished) {
? ? ? ? ? ? NSLog(@"正在緩存第%d張",i+1);
? ? ? ? ? ? //離開組
? ? ? ? ? ? dispatch_group_leave(group);
? ? ? ? }];
? ? }
? ? //通知緩存完成
? ? dispatch_group_notify(group, dispatch_get_main_queue(), ^{
? ? ? ? NSLog(@"緩存完成");
? ? });
}
- (NSArray*)getImageUrl{
? ? NSString *path = [[NSBundle mainBundle] pathForResource:@"imageUrl" ofType:@"plist"];
? ? return [NSArray arrayWithContentsOfFile:path];
}
創(chuàng)建沒有參數(shù)的代碼塊
@property(nonatomic,strong) dispatch_block_t block;
延時(shí)2s觸發(fā)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
? ? ? ? });
------------實(shí)例1------------
//如根據(jù)若干個(gè)url異步加載多張圖片,然后在都下載完成后合成一張整圖
? ? dispatch_group_t group = dispatch_group_create();
? ? dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
? ? dispatch_group_async(group, queue, ^{
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? });
? ? dispatch_group_async(group, queue, ^{
? ? });
? ? dispatch_group_notify(group, dispatch_get_main_queue(), ^{
? ? });
------------實(shí)例2------------
//dispatch_barrier_async(柵欄函數(shù))
/*
? ? 1.在它前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行拍皮,它后面的任務(wù)要等它執(zhí)行完成后才會(huì)開始執(zhí)行歹叮。
? ? 2.避免數(shù)據(jù)競(jìng)爭(zhēng)
?? ? */
? ? //創(chuàng)建并發(fā)隊(duì)列
? ? dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
? ? });
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
? ? });
? ? dispatch_barrier_async(queue, ^{
? ? ? ? NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
? ? });
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
? ? });
? ? dispatch_async(queue, ^{
? ? ? ? NSLog(@"任務(wù)5---%@",[NSThread currentThread]);
? ? });
------------實(shí)例3------------
NSLog(@"1");
? ? dispatch_sync(dispatch_get_main_queue(), ^{
? ? ? ? NSLog(@"2");
? ? });
? ? NSLog(@"3");
? ? //結(jié)果輸出1,主線程死鎖(主線程和主隊(duì)列相互等待)
附上Demo:?https://github.com/githubze/SKThread1