一直觉得多线程是一块难啃的骨头,倒不是因为他有多难,只是因为心里想这很难,在平时的学习和工作中总会有意无意的避开多线程的使用。今天写这篇文章倒不是因为掌握的多好,只是对多线程这块知识的随笔,下次看到也不至于太陌生。
IOS中实现多线程有三种方式:NSTHread,NSOperationQueue以及GCD(Grand Central Dispatch)。
以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在Mac OS X 10.6 ,iOS 4及以上也可用。
串行队列:
GCD 一次只执行一个任务,并且按照我们添加到队列的顺序来执行。因为同一时间不可能有两个任务访问临界区,所以不要担心临界区的数据安全问题;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 耗时的操作
dispatch_async(dispatch_get_main_queue(), ^{
// 更新界面
});
});
以上代码是将任务从主线程移到全局线程。因为这是一个 dispatch_async() ,Block 会被异步地提交,提交之后继续执行下面的代码,并不会等待block里面的代码直接完毕。GCD中可以将一组相关联的操作,定义到一个群组中,定义到群组中的操作可以当所有线程全部完成之后获得通知,这里举个例子,一个阅读软件,用户批量下载了很多本书,你不可能一本下完提醒一次,自然应该全部下完再提醒用户;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, queue, ^{
[self gcdSaleTicketWithName:@"gcd-1"];
});
dispatch_group_async(group, queue, ^{
[self gcdSaleTicketWithName:@"gcd-2"];
});
dispatch_group_async(group, queue, ^{
[self gcdSaleTicketWithName:@"gcd-3"];
});
//等的时间长的执行次数少,等待时间短的执行次数多
//群组任务完成接收通知
dispatch_group_notify(group, queue, ^{
NSLog(@"卖完了所有的票");
});
图解如下:
if (photo) { // 1
dispatch_barrier_async(self.concurrentPhotoQueue, ^{ // 2
[_photosArray addObject:photo]; // 3
dispatch_async(dispatch_get_main_queue(), ^{ // 4
[self postContentAddedNotification];
});
});
}
dispatch_apply(3, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^(size_t i) {
NSURL *url;
switch (i) {
case 0:
url = [NSURL URLWithString:kOverlyAttachedGirlfriendURLString];
break;
case 1:
url = [NSURL URLWithString:kSuccessKidURLString];
break;
case 2:
url = [NSURL URLWithString:kLotsOfFacesURLString];
break;
default:
break;
}
+(Ticket *)sharedTicket
{
//块代码里面只能使用外面的对象,不能修改外面的对象,要修改必须要加__block
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SharedInstance = [[Ticket alloc]init];
NSLog(@"ticket address :%@",SharedInstance);
});
return SharedInstance;
}
double delayInSeconds = 3.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self reloadArray];
[refreshControl endRefreshing];
});
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第2次操作,线程:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第3次操作,线程:%@", [NSThread currentThread]);
}];
[queue setMaxConcurrentOperationCount:2];
//第三次操作被同步锁挡在外面了
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
打印信息:
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第2次操作,线程:%@", [NSThread currentThread]);
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第3次操作,线程:%@", [NSThread currentThread]);
}];
[_queue setMaxConcurrentOperationCount:3];
[operation1 addDependency:operation2];
[operation2 addDependency:operation3];
//第三次操作被同步锁挡在外面了
[_queue addOperation:operation1];
[_queue addOperation:operation2];
[_queue addOperation:operation3];
假如三个任务互相依赖结果就是一个任务都不执行,互相等待;
一旦添加到operation queue,queue就拥有了这个Operation对象并且不能被删除,唯一能做的事情是取消。你可以调用Operation对象的cancel方法取消单个操作,也可以调用operation queue的cancelAllOperations方法取消当前queue中的所有操作。
// 取消单个操作
[operation3 cancel];
// 取消queue中所有的操作
[_queue cancelAllOperations];
一个是线程1被取消,一个是queue队列中所有任务被取消,这时候3的block也不会打印;
但是依赖3的其他两个任务会打印
如果需要在当前线程中处理operation完成后的结果,可以使用NSOperation的waitUntilFinished方法阻塞当前线程,等待operation完成。通常我们应该避免编写这样的代码,阻塞当前线程可能是一种简便的解决方案,但是它引入了更多的串行代码,限制了整个应用的并发性,同时也降低了用户体验。绝对不要在应用主线程中等待一个Operation,只能在第二或次要线程中等待。阻塞主线程将导致应用无法响应用户事件,应用也将表现为无响应。
// 会阻塞当前线程,等到某个operation执行完毕
[operation3 waitUntilFinished];
[queue waitUntilAllOperationsAreFinished];
在等待一个进程或者整个queue时,我们还可以往queue中添加其他的operation;
[queue addOperationWithBlock:^{
NSLog(@"等待之后的operation4添加");
}];
这时候4的打印会在以上三个任务完成以后
// 暂停queue
[queue setSuspended:YES];