iOS多線程實現(xiàn)方案

多線程實現(xiàn)方案.png
GCD(Grand Central Dispatch)
一、基本用法
GCD會自動利用更多的CPU內(nèi)核(比如雙核、四核)。
GCD會自動管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)、銷毀線程)。
只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼。
01 異步函數(shù)+并發(fā)隊列:開啟多條線程,并發(fā)執(zhí)行任務(wù) //start end...在多條線程
02 異步函數(shù)+串行隊列:開啟一條線程,串行執(zhí)行任務(wù)//start end...為串行隊列開啟一個線程
03 同步函數(shù)+并發(fā)隊列:不開線程,串行執(zhí)行任務(wù) //start...end在當前線程
04 同步函數(shù)+串行隊列:不開線程,串行執(zhí)行任務(wù)//start...end在當前線程
05 異步函數(shù)+主隊列:不開線程,在主線程中串行執(zhí)行任務(wù)//start end...主隊列:在主線程執(zhí)行
06 同步函數(shù)+主隊列:不開線程,串行執(zhí)行任務(wù)(注意死鎖發(fā)生)
07 使用sync函數(shù)往當前串行隊列中添加任務(wù),會卡住當前的(線程.)串行隊列

GCD.png
- 例子: 異步+串行隊列
NSLog(@"----start-%@" , [NSThread currentThread]);
dispatch_queue_t queue1 = dispatch_queue_create("download1", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue2, ^{
NSLog(@"---queue2222---%@",[NSThread currentThread]);
});
dispatch_async(queue1, ^{
NSLog(@"---download1---%@",[NSThread currentThread]);
});
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"---download2---%@",[NSThread currentThread]);
});
dispatch_async(queue1, ^{
NSLog(@"---download3---%@",[NSThread currentThread]);
});
dispatch_async(queue1, ^{
NSLog(@"---download4---%@",[NSThread currentThread]);
});
NSLog(@"----end-%@", [NSThread currentThread]);
//----start-<NSThread: 0x60000018cd80>{number = 1, name = main}
//----end-<NSThread: 0x60000018cd80>{number = 1, name = main}
//---download1---<NSThread: 0x6000001863c0>{number = 6, name = (null)}
//---queue2222---<NSThread: 0x6000001c4100>{number = 5, name = (null)}
//---download3---<NSThread: 0x6000001863c0>{number = 6, name = (null)}
//---download2---<NSThread: 0x60000018cd80>{number = 1, name = main}
//---download4---<NSThread: 0x6000001863c0>{number = 6, name = (null)}
- 例子2:死鎖
//使用sync往主隊列加任務(wù)并不一定死鎖。
//在子線程的當前串行隊列繼續(xù)加任務(wù)也會死鎖。
dispatch_async(dispatch_queue_create("q", DISPATCH_QUEUE_SERIAL), ^{
NSLog(@"-----%@",[NSThread currentThread]);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"不會死鎖===%@",[NSThread currentThread]);
});
dispatch_sync(dispatch_get_current_queue(), ^{
NSLog(@"會死鎖-----%@",[NSThread currentThread]);
});
});
//-----<NSThread: 0x6000036db1c0>{number = 6, name = (null)}
//不會死鎖===<NSThread: 0x6000036dcec0>{number = 1, name = main}
//卡死
二、其他方法
- dispatch_group_t隊列組 dispatch_group_async dispatch_group_notify
只能保證執(zhí)行當前線程任務(wù)完成后notify,不能保證二級任務(wù)
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
dispatch_group_async(group, q, ^{
for(NSInteger i = 0; i < 100; i++)
{
NSLog(@"++++%ld", (long)i);
}
dispatch_async(q, ^{
for(NSInteger i = 0; i < 200; i++)
{
NSLog(@"-----%ld", (long)i);
}
});
});
dispatch_group_notify(group, q, ^{
NSLog(@"======");
});
//++++99
//-----0
//======
//-----1
- dispatch_group_enter dispatch_group_leave 可以保證子任務(wù)
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
for(NSInteger i = 0; i < 100; i++)
{
NSLog(@"++++%ld", (long)i);
}
dispatch_group_leave(group);
dispatch_group_enter(group);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for(NSInteger i = 0; i < 200; i++)
{
NSLog(@"-----%ld", (long)i);
}
dispatch_group_leave(group);//寫在async函數(shù)里才可
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"======");
});
- dispatch_barrier_async柵欄函數(shù),用來控制并發(fā)隊列的執(zhí)行順序
- dispatch_after延遲執(zhí)行
//表名2秒鐘之后調(diào)用run
// [self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
/*
第一個參數(shù):延遲時間
第二個參數(shù):要執(zhí)行的代碼
*/
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
NSLog(@"---%@",[NSThread currentThread]);
});
- dispatch_once_t整個程序運行后只執(zhí)行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
});
- dispatch_apply創(chuàng)建多條線程執(zhí)行
//創(chuàng)建隊列(并發(fā)隊列)
dispatch_queue_t queue = dispatch_queue_create("com.downloadqueue", DISPATCH_QUEUE_CONCURRENT);
/*
第一個參數(shù):迭代的次數(shù)
第二個參數(shù):在哪個隊列中執(zhí)行
第三個參數(shù):block要執(zhí)行的任務(wù)
*/
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"%zd--%@",index,[NSThread currentThread]);
});
//文件在哪個地方(文件夾)
NSString *form = @"/Users/xiaomage/Desktop/form";
//要剪切到什么地方
NSString *to = @"/Users/xiaomage/Desktop/to";
NSFileManager *manager = [NSFileManager defaultManager];
NSArray *subpaths = [manager subpathsAtPath:form];
//NSDirectoryEnumerator *enumer = [manager enumeratorAtPath:to];//可以打印嵌套文件夾下文件路徑
//NSDirectoryEnumerator *enumer = [manager contentsOfDirectoryAtPath:to error:nil];
//for (NSDirectoryEnumerator *en in enumer) {
// NSLog(@"%@",en);
// }
// NSLog(@"%@",subpaths);
NSInteger count = [subpaths count];
for (NSInteger i = 0; i<count; i++) {
//拼接文件全路徑
// NSString *fullPath = [form stringByAppendingString:<#(nonnull NSString *)#>]
NSString *subpath = subpaths[i];
NSString *fullPath = [form stringByAppendingPathComponent:subpath];
//拼接目標文件全路徑
NSString *fileName = [to stringByAppendingPathComponent:subpath];
//剪切操作
[manager moveItemAtPath:fullPath toPath:fileName error:nil];
NSLog(@"%@--%@",fullPath,fileName);
}
NSOperationQueue
一、NSOperation
- NSInvocationOperation
/*
第一個參數(shù):目標對象
第二個參數(shù):選擇器,要調(diào)用的方法
第三個參數(shù):方法要傳遞的參數(shù)
*/
// NSInvocationOperation *op = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download) object:nil];
//
// //啟動操作
// [op start];
- NSBlockOperation
//1.封裝操作//在主線程
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1------%@",[NSThread currentThread]);
}];
//2.追加操作//在子線程中并發(fā)執(zhí)行
[op1 addExecutionBlock:^{
NSLog(@"2------%@",[NSThread currentThread]);
}];
[op1 addExecutionBlock:^{
NSLog(@"3------%@",[NSThread currentThread]);
}];
- 寫一個類繼承NSOperation,重新main方法。[op start];時調(diào)用main方法。
二、 NSOperationQueue
1.將操作放入,系統(tǒng)自動異步執(zhí)行
- NSInvocationOperation添加到操作隊列
/*
主隊列:凡是放到主隊列里面的任務(wù)都在主線程執(zhí)行[NSOperationQueue mainQueue]
非主隊列:alloc int,同時具備了并發(fā)和串行的功能,默認是并發(fā)隊列
*/
//1.創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download2) object:nil];
NSInvocationOperation *op3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(download3) object:nil];
//3.添加操作到隊列,系統(tǒng)自動異步執(zhí)行
[queue addOperation:op1]; //[op1 start]
[queue addOperation:op2];
[queue addOperation:op3];
-(void)download1
{
NSLog(@"download1---%@",[NSThread currentThread]);
}
- NSBlockOperation添加到操作隊列
//1.創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);
}];
[op2 addExecutionBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
}];
//3.添加操作到隊列
[queue addOperation:op1]; //[op1 start]
[queue addOperation:op2];
//簡便方法
[queue addOperationWithBlock:^{
NSLog(@"4----%@",[NSThread currentThread]);
}];
- 繼承類類型
//1.創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//2.封裝操作
XMGOperation *op1 = [[XMGOperation alloc]init];
XMGOperation *op2 = [[XMGOperation alloc]init];
//3.添加操作到隊列
[queue addOperation:op1]; //[op1 start]
[queue addOperation:op2];
2.其他
- maxConcurrentOperationCount
默認是最大并發(fā)數(shù)-1是并發(fā)隊列,如果最大并發(fā)數(shù)>1,并發(fā)
如果最大并發(fā)數(shù)==1,串行隊列(也可能有多個線程) - suspended YES暫停NO恢復(fù)
只能暫停隊列中后面的操作,不能暫停正在執(zhí)行的操作。 - cancelAllOperations 取消,不再執(zhí)行 operation.isCancelled判斷操作是否已取消
- 操作監(jiān)聽和依賴
//1.創(chuàng)建隊列
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
NSOperationQueue *queue1 = [[NSOperationQueue alloc]init];
//2.封裝操作
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"1----%@",[NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"2----%@",[NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"3----%@",[NSThread currentThread]);
}];
NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"4----%@",[NSThread currentThread]);
}];
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
for (NSInteger i=0; i<1000; i++) {
NSLog(@"5-%zd---%@",i,[NSThread currentThread]);
}
}];
op4.completionBlock = ^{
NSLog(@"op4已經(jīng)完成了---%@",[NSThread currentThread]);
};
//添加操作依賴,注意不能循環(huán)依賴
//也可以依賴其他隊列的操作
[op1 addDependency:op5];
[op1 addDependency:op4];
//添加操作到隊列
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
[queue addOperation:op4];
[queue1 addOperation:op5];
- 線程間通信
//1.創(chuàng)建隊列
NSOperationQueue *queue= [[NSOperationQueue alloc]init];
//2.下載圖片
[queue addOperationWithBlock:^{
//2.1.確定要下載網(wǎng)絡(luò)圖片的url地址,一個url唯一對應(yīng)著網(wǎng)絡(luò)上的一個資源
NSURL *url = [NSURL URLWithString:@"http://p6.qhimg.com/t01d2954e2799c461ab.jpg"];
//2.2.根據(jù)url地址下載圖片數(shù)據(jù)到本地(二進制數(shù)據(jù))
NSData *data = [NSData dataWithContentsOfURL:url];
//2.3.把下載到本地的二進制數(shù)據(jù)轉(zhuǎn)換成圖片
UIImage *image = [UIImage imageWithData:data];
//3.回到主線程刷新UI
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
NSLog(@"%@----",[NSThread currentThread]);
}];
}];
NSThread
/*
第一個參數(shù):目標對象
第二個參數(shù):選擇器,調(diào)用哪個方法
第三個參數(shù):前面方法需要傳遞的參數(shù)
*/
NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil];
//設(shè)置基本屬性
thread1.name = @"線程1";
//線程優(yōu)先級
[thread1 setThreadPriority:1.0];//默認0.5,cpu調(diào)度線程的概率
//開啟線程
[thread1 start];
/*
第一個參數(shù):選擇器,調(diào)用哪個方法
第二個參數(shù):目標對象
第三個參數(shù):前面方法需要傳遞的參數(shù)
*/
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"參數(shù)"];
/*
第三種創(chuàng)建線程的方式
特點:默認開啟線程
*/
[self performSelectorInBackground:@selector(run:) withObject:@"后臺線程"];
pthread了解
//創(chuàng)建線程
pthread_t thread;
/*
第一個參數(shù):線程對象
第二個參數(shù):線程屬性
第三個參數(shù):void *(*)(void *) 指向函數(shù)的指針
第四個參數(shù):函數(shù)的參數(shù)
*/
pthread_create(&thread, NULL, run, NULL);
pthread_t thread1;
pthread_create(&thread1, NULL, run, NULL);
//void *(*)(void *)
void *run(void *param)
{
// NSLog(@"---%@-",[NSThread currentThread]);
for (NSInteger i =0 ; i<10000; i++) {
NSLog(@"%zd--%@-",i,[NSThread currentThread]);
}
return NULL;
}