多线程一直是很操蛋的一个话题,其实如果你理解了很简单,没理解很麻烦;在OC中多线程通常有以下四种

四种线程 pthread_t ,NSThread, GCD,NSOperation+NSOperationQueue

第一种 pthread_t

严格的来说pthread_t并不仅仅属于OC的线程,但是OC牛逼的地方在于它完全兼容C和C++代码,这个玩意个人觉得只需要了解;毕竟这东西的确用的不多,而且相当蛋疼,我们用一个例子说明下这东西的用法 ,既然说了是C语言代码那么就要用C语言的代码搞一搞多线程了,OC需要使用直接复制过去就可以

#include <stdio.h>
#include <pthread.h>void testThread();
void *start(void *data);int main(int argc, char const *argv[])
{ puts("================  start =================");testThread();puts("================  end =================");int i;for(i=0;i<=10;i++){printf("main ===  %d\n", i);}return 0;
}
void testThread(){pthread_t pthread;pthread_create(&pthread,NULL,start,NULL);
}
void *start(void *data){puts("this is thread test !!");int i;for(i=0;i<=5;i++){printf("start === %d\n", i);}return NULL;
}

OC中需要导入头文件,如上图
输出结果如下图

gcc 编译C文件这里就不多解释了,上面的结果说明了一切,至于其他的用法就不多解释了 ,以上就是所谓的 pthread_t的用法了,我们仅作为了解了

第二种 NSThread

NSThread 分为两种:一种是自启动,一种是手动启动;两种线程的子线程体都可以是block或者自定义方法

+ (void)detachNewThreadWithBlock:(void (^)(void))block;
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument;
- (instancetype)initWithBlock:(void (^)(void))block;

自启动:顾名思义就是创建这个线程就会自动执行线程的方法
手动启动:需要手动调用线程的start方法才可以启动
上代码,看看如何使用

-(void)testThreadBlock{NSThread *thread = [[NSThread alloc] initWithBlock:^{for (int i=0; i<=10; i++) {NSLog(@"thread  +++++ %d",i);}}];[thread start];[NSThread detachNewThreadWithBlock:^{for (int i=0; i<=10; i++) {NSLog(@"NSThread _____ %d",i);}}];
}
-(void)testThreadSelector{NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction1) object:nil];[thread start];[NSThread detachNewThreadSelector:@selector(threadAction2) toTarget:self withObject:nil];}
-(void)threadAction1{for (int i=0; i<=10; i++) {NSLog(@"thread  +++++ %d",i);}
}
-(void)threadAction2{for (int i=0; i<=10; i++) {NSLog(@"NSThread _____ %d",i);}
}

看下日志输出

在NSThread中有一个属性用的比较多 threadPriority 线程优先级属性,这个属性取值是从 0 到 1.0 ;数值越大优先级就越高,通常如果不设置这个值的话系统默认这个值是 0.5

如果把这个值越大:有更高的概率先执行,反之则先执行的概率较低我们比较下这是成0.1 和 0.9 比较下debug的日志

设置成0.1的时候,我们日志的前面大部分是main;当设置成0.9的是,日志前面大部分是thread
类方法和对象方法都可以设置 threadPriority 至于类方法怎么使用其实Apple的API已经讲的很清楚。下面NSThread总结下类方法和对象方法的异同点

方法属性 类方法 对象方法
创建 类方法创建 对象方法创建
支持block 支持 支持
支持SEL 支持 支持
启动 自启动 start方法启动
退出 exit方法退出 cancel方法退出
默认优先级 0.5 0.5
可设置优先级 可设置 可设置,可以单个线程设置

除此之外NSThread 对 NSObject进行了扩展,我们偶尔能用到的开一个新线程执行 和 放在后台执行;但是要注意的是延时执行是RunLoop相关的,但是我猜想跟线程应该有些关系。。。

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg ;

上面的两个方法其实是OC给我们提供了一种简单的开启新线程的方法,这里就不演示了,方法的名称说明了一切

第三种 GCD

首先GCD是啥子 ? 最好的解释是 基于C语言的一种比较装逼的高级的且适用于OC的多线程 我觉得你能够接触到多线程,想必对GCD会有一点了解 ;回到我们的源头,为什么要用多线程? 其实多线程无非就是用来解决 处理些长时间耗时的或者阻塞当前代码运行的 一种技术吧;比如说大文件下载,列表加载图片等等。。 讲到GCD之前,先引入一个实例

在这个页面要下载9张图片,如果使用多线程肯定会滑动卡顿的,可以这么理解:主线程负责UI跟用户的交互,子线程负责下载图片;当主线程去下载图片的时候就会影响用户交互也就是卡顿 —- 题外话 。。。

上面有9张图片在下载, 下载每一张图片的这个过程我们称之为任务 ,也就是上图有9个任务
那么上面的9个任务组成了一个任务组,我们称这个任务组叫队列

任务:耗时操作
队列:多个任务的集合

也就是GCD的操作是基于 队列和任务了,那么我们就来探讨下队列;队列是任务的容器,队列分为两种,有些地方也分为三种;串行队列,并行队列,主队列; ,任务也分为两种 : 同步任务 和 异步任务 ;也就是 任务和队列的组合形式 一共有6中 ,我们逐个来看下

  • 串行队列 同步任务
  • 串行队列 异步任务
  • 并行队列 同步任务
  • 并行队列 异步任务
  • 主队列 同步任务
  • 主队列 异步任务

1 串行队列 同步任务

串行队列创建

-(void)queueTest1{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);dispatch_sync(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/a1.jpg"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_sync1 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});dispatch_sync(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/a2.jpg"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_sync2 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));NSLog(@"after download  ====== %ld",[NSThread currentThread].hash);
}

队列创建包含两个参数
第一个是队列的标识 “hebiao.queue” 自定义标识
第二个是串行队列的标志 DISPATCH_QUEUE_SERIAL 系统常量

dispatch_queue_t queue = dispatch_queue_create("hebiao.queue", DISPATCH_QUEUE_SERIAL);

创建一个串行队列

 dispatch_sync(queue, ^{});

创建一个同步任务 , 如何知道是同步任务还是 异步任务了 ? 我们看下日志输出

2017-08-30 09:33:15.677615+0800 TestNSProxy[9889:3274457] currentThread ====== 6174428672
2017-08-30 09:33:15.677692+0800 TestNSProxy[9889:3274457] mainThread  ====== 6174428672
2017-08-30 09:33:23.107414+0800 TestNSProxy[9889:3274457] dispatch_sync1 ======= 6174428672   imagesize = {2592, 1552}
2017-08-30 09:33:23.226778+0800 TestNSProxy[9889:3274457] dispatch_sync2 ======= 6174428672   imagesize = {500, 313}
2017-08-30 09:33:23.226852+0800 TestNSProxy[9889:3274457] after download  ====== 6174428672

我们发现线程的hash值是一样的然后 下载图片算是一个耗时操作并且第一张图片下载完成之后就下载第二张,按照代码的顺序所以我们可以得出结论如下 串行队列 同步任务: 不开启新的线程,按队列的顺序执行

2 串行队列 异步任务

串行队列创建 跟上面是一样的 。。


-(void)queueTest2{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);dispatch_queue_t queue = dispatch_queue_create("hebiao.queue", DISPATCH_QUEUE_SERIAL);dispatch_async(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/a1.jpg"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_async1 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});dispatch_async(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/a2.jpg"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_async2 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});NSLog(@"after download  ====== %ld",[NSThread currentThread].hash);
}

队列创建包含两个参数
第一个是队列的标识 “hebiao.queue” 自定义标识
第二个是串行队列的标志 DISPATCH_QUEUE_SERIAL 系统常量

dispatch_queue_t queue = dispatch_queue_create("hebiao.queue", DISPATCH_QUEUE_SERIAL);

创建一个串行队列 , 这个跟上面是一样的 ,不同的是异步任务

 dispatch_async(queue, ^{});

创建一个异步任务; 我们发现 这两个很像 同步任务dispatch_sync 和异步任务dispatch_async 就差一个字母 a 看下日志

2017-08-30 09:44:31.416907+0800 TestNSProxy[9893:3277114] currentThread ====== 6241615616
2017-08-30 09:44:31.416957+0800 TestNSProxy[9893:3277114] mainThread  ====== 6241615616
2017-08-30 09:44:31.417000+0800 TestNSProxy[9893:3277114] after download  ====== 6241615616
2017-08-30 09:44:42.403647+0800 TestNSProxy[9893:3277155] dispatch_async1 ======= 6243653760   imagesize = {2592, 1552}
2017-08-30 09:44:42.530342+0800 TestNSProxy[9893:3277155] dispatch_async2 ======= 6243653760   imagesize = {500, 313}

我们异步任务中线程的hash值和主线程不一样,然后 下载图片算是一个耗时操作并且第一张图片下载完成之后就下载第二张,按照代码的顺序执行,所以我们可以得出结论如下 串行队列 异步步任务: 为所有任务开启一个新的线程,按队列的顺序执行

3 并行队列 同步任务

串行队列和并行队列关键字修饰不一样 ,直接上代码

-(void)queueTest3{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);dispatch_queue_t queue = dispatch_queue_create("hebiao.queue", DISPATCH_QUEUE_CONCURRENT);dispatch_sync(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/a1.jpg"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_sync1 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});dispatch_sync(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/tomcat.png"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_sync2 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});NSLog(@"after download  ====== %ld",[NSThread currentThread].hash);}

队列创建包含两个参数
第一个是队列的标识 “hebiao.queue” 自定义标识
第二个是并行队列的标志 DISPATCH_QUEUE_CONCURRENT 系统常量

dispatch_queue_t queue = dispatch_queue_create("hebiao.queue", DISPATCH_QUEUE_CONCURRENT);

创建一个串行队列

 dispatch_sync(queue, ^{});

创建一个同步任务 我们看下日志输出

2017-08-30 09:55:27.481648+0800 TestNSProxy[9905:3280774] currentThread ====== 6174477056
2017-08-30 09:55:27.481706+0800 TestNSProxy[9905:3280774] mainThread  ====== 6174477056
2017-08-30 09:55:35.257421+0800 TestNSProxy[9905:3280774] dispatch_sync1 ======= 6174477056   imagesize = {2592, 1552}
2017-08-30 09:55:35.295198+0800 TestNSProxy[9905:3280774] dispatch_sync2 ======= 6174477056   imagesize = {146, 92}
2017-08-30 09:55:35.295324+0800 TestNSProxy[9905:3280774] after download  ====== 6174477056

我们发现只要是同步任务,不管是并行队列和串行队列 输出是一样的 ,不开启新线程并且顺序执行 我们可以得出结论如下 并行队列 同步任务: 不开启新的线程,按队列的顺序执行

4 并行队列 异步任务

直接上代码 。。

-(void)queueTest4{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);dispatch_queue_t queue = dispatch_queue_create("hebiao.queue", DISPATCH_QUEUE_CONCURRENT);dispatch_async(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/a1.jpg"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_async1 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});dispatch_async(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/tomcat.png"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_async2 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});NSLog(@"after download  ====== %ld",[NSThread currentThread].hash);}

我们直接输出日志,在输出日志之前先申明下 https://hebiao.online/img/a1.jpg 这个图片较大, 而https://hebiao.online/img/tomcat.png这个图片很小 ,我们看下日志

2017-08-30 10:05:52.386516+0800 TestNSProxy[9909:3283332] currentThread ====== 6174457024
2017-08-30 10:05:52.386569+0800 TestNSProxy[9909:3283332] mainThread  ====== 6174457024
2017-08-30 10:05:52.386616+0800 TestNSProxy[9909:3283332] after download  ====== 6174457024
2017-08-30 10:05:52.845416+0800 TestNSProxy[9909:3283372] dispatch_async2 ======= 6174523776   imagesize = {146, 92}
2017-08-30 10:05:59.969279+0800 TestNSProxy[9909:3283369] dispatch_async1 ======= 6241632640   imagesize = {2592, 1552}

我们发现 ,有三个不同的线程hash值;也就是除了主线程之外分别为两个任务开启了两个子线程,并且不是按照顺序执行的,而且我们发现图片小的先下载完成,总结下并行队列 异步步任务: 为每个任务开启新的线程,不按队列的顺序执行

5 主队列 同步任务

上代码

-(void)queueTest5{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);dispatch_queue_t queue = dispatch_get_main_queue();dispatch_sync(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/a1.jpg"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_sync1 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});dispatch_sync(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/tomcat.png"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_sync2 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});NSLog(@"after download  ====== %ld",[NSThread currentThread].hash);}

创建主队列

 dispatch_queue_t queue = dispatch_get_main_queue();

其他的地方是一样的,但是执行的时候就报错了 。。。。。
总结下主队列 同步任务: 直接报错

6 主队列 异步任务

上代码

-(void)queueTest6{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);dispatch_queue_t queue = dispatch_get_main_queue();dispatch_async(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/a1.jpg"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_async1 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});dispatch_async(queue, ^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/tomcat.png"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"dispatch_async2 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));});NSLog(@"after download  ====== %ld",[NSThread currentThread].hash);}

跟上面类似,只是同步和异步的区别 ,然后看下日志的输出

2017-08-30 10:29:50.184149+0800 TestNSProxy[9936:3290719] currentThread ====== 6174437632
2017-08-30 10:29:50.184198+0800 TestNSProxy[9936:3290719] mainThread  ====== 6174437632
2017-08-30 10:29:50.184225+0800 TestNSProxy[9936:3290719] after download  ====== 6174437632
2017-08-30 10:30:00.720892+0800 TestNSProxy[9936:3290719] dispatch_async1 ======= 6174437632   imagesize = {2592, 1552}
2017-08-30 10:30:00.759890+0800 TestNSProxy[9936:3290719] dispatch_async2 ======= 6174437632   imagesize = {146, 92}

看日志我们发现,线程hash值是一样的,但是执行的顺序不一样 总结下主队列 异步任务: 不开启新的线程,不按队列的顺序执行
总结下以上几种队列

队列 同步任务 异步任务
串行队列 不开新线程,顺序执行 为任务开启一个新线程,顺序执行
并行队列 不开新线程,顺序执行 为每个任务开启一个新线程,不按顺序执行
主队列 无效报错 不开新线程 ,不按顺序执行

结论

同步任务:不开启新线程,顺序执行
异步任务:主队列不开新线程

第四种 NSOperation+NSOperationQueue

NSOperation 按照GCD的理解就是任务
NSOperationQueue 同样按照GCD的理解就是队列
NSOperation 有两个子类 NSBlockOperation 和 NSInvocationOperation 通过名称不难看出,一个是block方法,一个是SEL方法;我们一般使用的是NSOperation的子类或者自定义一个类继承NSOperation 跟NSThread是类似的 ,分别来看下用法

1 NSBlockOperation

-(void)queueTest7{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);// NSBlockOperation *operatiion = [[NSBlockOperation alloc] init]; 两种都一样NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation1  ====== %ld",[NSThread currentThread].hash);}];[operation addExecutionBlock:^{NSLog(@"operation2  ====== %ld",[NSThread currentThread].hash);}];[operation start];}2017-08-30 11:28:55.177034+0800 TestNSProxy[9955:3301574] currentThread ====== 6241573952
2017-08-30 11:28:55.177090+0800 TestNSProxy[9955:3301574] mainThread  ====== 6241573952
2017-08-30 11:28:55.177263+0800 TestNSProxy[9955:3301617] operation1  ====== 6174533376
2017-08-30 11:28:55.177277+0800 TestNSProxy[9955:3301617] operation2  ====== 6174533376

单纯的 NSBlockOperation 会开启一个新线程并且按顺序执行; 跟我们上面提到的 串行队列 异步任务 很像

2 NSInvocationOperation

先上代码

-(void)queueTest8{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(action:) object:NULL];[operation start];
}
-(void)action:(id)sender{NSLog(@"operation  ====== %ld",[NSThread currentThread].hash);
}2017-08-30 11:48:05.237857+0800 TestNSProxy[9965:3306128] currentThread ====== 6174532032
2017-08-30 11:48:05.237909+0800 TestNSProxy[9965:3306128] mainThread  ====== 6174532032
2017-08-30 11:48:05.238099+0800 TestNSProxy[9965:3306128] operation  ====== 6174532032

这个类很尴尬 , 只有一个所谓的任务,而且没有开启新的线程

3 NSOperationQueue

会有这么一个问题,如果我想搞一个 并行队列 异步任务 了 ? 按照上面的方式貌似没有什么搞头 ,那么 。。。 就要引入 NSOperationQueue ,先来看下NSOperationQueue的初始化

-(void)queueTest9{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);NSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperationWithBlock:^{NSLog(@"queue  ====== %ld",[NSThread currentThread].hash);}];NSOperationQueue *mqueue = [NSOperationQueue mainQueue];[mqueue addOperationWithBlock:^{NSLog(@"mqueue  ====== %ld",[NSThread currentThread].hash);}];
}2017-08-30 14:10:29.330361+0800 TestNSProxy[10105:3345221] currentThread ====== 6174459328
2017-08-30 14:10:29.330427+0800 TestNSProxy[10105:3345221] mainThread  ====== 6174459328
2017-08-30 14:10:29.331572+0800 TestNSProxy[10105:3345270] queue  ====== 6241580672
2017-08-30 14:10:29.336198+0800 TestNSProxy[10105:3345221] mqueue  ====== 6174459328

NSOperationQueue 初始化有方法有两种,一种是 alloc 一种是 mainQueue ;我们发现 alloc创建的queue是开启了一个新的线程,而mainQueue 并没有开启新线程 ;还有 一点比较重要的是 NSOperationQueue 无需手动启动
我们可以把NSOperationQueue 跟前面的 NSOperation 关联起来

-(void)queueTest10{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);NSBlockOperation *blockOperation1 = [[NSBlockOperation alloc] init];[blockOperation1 addExecutionBlock:^{NSLog(@"blockOperation1 ======= %ld   ",[NSThread currentThread].hash);}];NSInvocationOperation *blockOperation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(opAction:) object:nil];NSLog(@"  === over === ");NSOperationQueue *queue = [[NSOperationQueue alloc] init];[queue addOperation:blockOperation1];[queue addOperation:blockOperation2];
}
-(void)opAction:(id)sender{NSLog(@"blockOperation2 ======= %ld  ",[NSThread currentThread].hash );
}2017-08-30 14:33:28.151707+0800 TestNSProxy[10122:3352107] currentThread ====== 6174484288
2017-08-30 14:33:28.151762+0800 TestNSProxy[10122:3352107] mainThread  ====== 6174484288
2017-08-30 14:33:28.152059+0800 TestNSProxy[10122:3352107]   === over ===
2017-08-30 14:33:28.152201+0800 TestNSProxy[10122:3352159] blockOperation1 ======= 6176507712
2017-08-30 14:33:28.152299+0800 TestNSProxy[10122:3352159] blockOperation2 ======= 6176507712

通过上面的代码我们把NSOperationQueue 和 NSOperation 联系在一起了,但是这貌似没有跟GCD相比少点什么 。。。 如何让多个任务同时执行了 ?

-(void)queueTest11{NSLog(@"currentThread ====== %ld",[NSThread currentThread].hash);NSLog(@"mainThread  ====== %ld",[NSThread mainThread].hash);NSOperationQueue *queue = [[NSOperationQueue alloc] init];queue.maxConcurrentOperationCount = 1;[queue addOperationWithBlock:^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/a1.jpg"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"queue1 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));}];[queue addOperationWithBlock:^{NSLog(@"queue2 ====== %ld",[NSThread currentThread].hash);}];[queue addOperationWithBlock:^{NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:@"https://hebiao.online/img/tomcat.png"]];UIImage *img = [[UIImage alloc] initWithData:data];NSLog(@"queue3 ======= %ld   imagesize = %@",[NSThread currentThread].hash ,NSStringFromCGSize(img.size));}];[queue addOperationWithBlock:^{NSLog(@"queue4 ====== %ld",[NSThread currentThread].hash);}];[queue addOperationWithBlock:^{NSLog(@"queue5 ====== %ld",[NSThread currentThread].hash);}];NSLog(@"  === over === ");
}2017-08-30 14:45:24.603104+0800 TestNSProxy[10134:3356916] currentThread ====== 6241543232
2017-08-30 14:45:24.603159+0800 TestNSProxy[10134:3356916] mainThread  ====== 6241543232
2017-08-30 14:45:24.603443+0800 TestNSProxy[10134:3356916]   === over ===
2017-08-30 14:45:32.057217+0800 TestNSProxy[10134:3356962] queue1 ======= 6174480896   imagesize = {2592, 1552}
2017-08-30 14:45:32.058261+0800 TestNSProxy[10134:3356963] queue2 ====== 6174466304
2017-08-30 14:45:32.150285+0800 TestNSProxy[10134:3356963] queue3 ======= 6174466304   imagesize = {146, 92}
2017-08-30 14:45:32.150746+0800 TestNSProxy[10134:3356963] queue4 ====== 6174466304
2017-08-30 14:45:32.150973+0800 TestNSProxy[10134:3356963] queue5 ====== 6174466304

NSOperationQueue 提供了 一个 maxConcurrentOperationCount 最大线程数量;我们可以这么理解,除了主线程之外,最多可以开启多少个任务数量,有点像迅雷下载 。。。。 上面的任务数设置为1,但是看到上面的日志 ,我觉得这个说法还得加个修饰 同时开启的最大线程数量
当我把上面的数值调整的时候

queue.maxConcurrentOperationCount = 5;2017-08-30 14:48:43.145571+0800 TestNSProxy[10138:3358375] currentThread ====== 6176514752
2017-08-30 14:48:43.145625+0800 TestNSProxy[10138:3358375] mainThread  ====== 6176514752
2017-08-30 14:48:43.145863+0800 TestNSProxy[10138:3358375]   === over ===
2017-08-30 14:48:43.146940+0800 TestNSProxy[10138:3358423] queue2 ====== 6176556160
2017-08-30 14:48:43.150508+0800 TestNSProxy[10138:3358422] queue4 ====== 6176549760
2017-08-30 14:48:43.150566+0800 TestNSProxy[10138:3358422] queue5 ====== 6176549760
2017-08-30 14:48:44.280059+0800 TestNSProxy[10138:3358423] queue3 ======= 6176556160   imagesize = {146, 92}
2017-08-30 14:48:50.769027+0800 TestNSProxy[10138:3358424] queue1 ======= 6176593088   imagesize = {2592, 1552}

我们发现得到的输出顺序变了 。。。。 我们甚至可以得出这样的一个结论
queue.maxConcurrentOperationCount = 1 的时候 NSOperationQueue 为串行队列
而当maxConcurrentOperationCount > 1 的时候 NSOperationQueue 并行队列 ;
并且 maxConcurrentOperationCount 默认为 1

另外NSOperation 还有一个比较常用的功能就是 NSOperation 是可以相互依赖的,有点像Jar包依赖;举个简单的例子,我要吃饭,但是我必须用碗把饭先盛着再吃,把饭盛到碗了这个动作可以理解为依赖
没有依赖之前

-(void)queueTest12{NSOperationQueue *queue = [[NSOperationQueue alloc] init];NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation1  ====== %ld",[NSThread currentThread].hash);}];NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation2  ====== %ld",[NSThread currentThread].hash);}];NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation3  ====== %ld",[NSThread currentThread].hash);}];NSBlockOperation *operation4 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation4  ====== %ld",[NSThread currentThread].hash);}];NSBlockOperation *operation5 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation5  ====== %ld",[NSThread currentThread].hash);}];[queue addOperation:operation1];[queue addOperation:operation2];[queue addOperation:operation3];[queue addOperation:operation4];[queue addOperation:operation5];
}2017-08-30 15:05:58.261291+0800 TestNSProxy[10151:3363635] operation2  ====== 6176545728
2017-08-30 15:05:58.261399+0800 TestNSProxy[10151:3363631] operation1  ====== 6243625856
2017-08-30 15:05:58.261440+0800 TestNSProxy[10151:3363635] operation3  ====== 6176545728
2017-08-30 15:05:58.261504+0800 TestNSProxy[10151:3363631] operation4  ====== 6243625856
2017-08-30 15:05:58.261524+0800 TestNSProxy[10151:3363635] operation5  ====== 6176545728

1-5是顺序执行的 , 一旦加入了依赖 就变化 了 。。


-(void)queueTest12{NSOperationQueue *queue = [[NSOperationQueue alloc] init];NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation1  ====== %ld",[NSThread currentThread].hash);}];NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation2  ====== %ld",[NSThread currentThread].hash);}];NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation3  ====== %ld",[NSThread currentThread].hash);}];NSBlockOperation *operation4 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation4  ====== %ld",[NSThread currentThread].hash);}];NSBlockOperation *operation5 = [NSBlockOperation blockOperationWithBlock:^{NSLog(@"operation5  ====== %ld",[NSThread currentThread].hash);}];[operation1 addDependency:operation2];[operation2 addDependency:operation3];[operation3 addDependency:operation4];[operation4 addDependency:operation5];[queue addOperation:operation1];[queue addOperation:operation2];[queue addOperation:operation3];[queue addOperation:operation4];[queue addOperation:operation5];
}2017-08-30 15:07:55.438561+0800 TestNSProxy[10153:3364304] operation5  ====== 6241643648
2017-08-30 15:07:55.438650+0800 TestNSProxy[10153:3364304] operation4  ====== 6241643648
2017-08-30 15:07:55.438685+0800 TestNSProxy[10153:3364304] operation3  ====== 6241643648
2017-08-30 15:07:55.438714+0800 TestNSProxy[10153:3364304] operation2  ====== 6241643648
2017-08-30 15:07:55.438743+0800 TestNSProxy[10153:3364304] operation1  ====== 6241643648

顺序变了 , 优先执行 被依赖的 NSBlockOperation。。。。。。
兵无常势 水无常形 具体的项目具体操作 。。

ios多线程浅谈和使用相关推荐

  1. 【转】从Mac/OS和iOS开放源码浅谈UNIX家谱

    [转]从Mac/OS和iOS开放源码浅谈UNIX家谱 阅读数:1245 苹果公司在各类开源项目中长期贡献着自己的力量,但其UNIX系统技术一直都属于闭源阵营(这一点可以从NUX OS阵营和家谱图中得到 ...

  2. iOS之浅谈纯代码控制UIViewController视图控制器跳转界面的几种方法

    一.最普通的视图控制器UIViewContoller 一个普通的视图控制器一般只有模态跳转的功能(ipad我不了解除外,这里只说iPhone),这个方法是所有视图控制器对象都可以用的,而实现这种功能, ...

  3. iOS 送审浅谈:1.4.1、2.1、2.5.2、2.5.4、4.2.3、5.2.5

    目录 Guideline 1.4.1 - Safety - Physical Harm Guideline 2.1 - Information Needed: Guideline 2.1 - Info ...

  4. iOS XML浅谈

    XML简介 XML出身名门,W3C制定,微软和IBM曾经共同大力推荐过的数据格式. XML指可扩展标记语言(Extensible Markup Language). 被设计用来传输和存储数据.在以前是 ...

  5. 浅谈 unix, linux, ios, android 区别和联系

    浅谈 unix, linux, ios, android 区别和联系 网上的答案并不是很好,便从网上整理的相对专业的问答. 1.UNIX 和 Linux UNIX 操作系统(尤尼斯), 是一个强大的多 ...

  6. iOS实录15:浅谈iOS Crash

    导语:在当前的iOS开发中,虽然ARC为开发者解决了手动内存管理时代 的许多麻烦,但是内存方面的问题依然是产生iOS Crash的元凶之一,本文介绍内存方面,有关僵尸对象.野指针.内存泄漏.废弃内存这 ...

  7. Unity iOS打开AppStore评星页面,浅谈Application.OpenURL()方法。

    http://fairwoodgame.com/blog/?p=38 Unity iOS打开AppStore评星页面,浅谈Application.OpenURL()方法. Posted in  Uni ...

  8. 浅谈多核CPU、多线程与并行计算

    浅谈多核CPU.多线程与并行计算 xiaofei0859 2017-05-09 17:07:11  3646  收藏 展开 0.前言 笔者用过MPI和C#线程池,参加过比赛,有所感受,将近一年来,对多 ...

  9. 多线程之旅之四——浅谈内存模型和用户态同步机制

     用户态下有两种同步结构的 volatile construct: 在简单数据类型上原子性的读或者写操作   interlocked construct:在简单数据类型上原子性的读和写操作 (在这里还 ...

最新文章

  1. linux 循环shell脚本,shell脚本的使用---for循环
  2. ​全球首个视频实验期刊JOVE征稿:植物微生物组学方法专刊(牛犇、韦中、高峥、王蒙岑)...
  3. 传送门(portal)
  4. dos的echo on与echo off命令用法实例讲解
  5. 詹金斯搭建_詹金斯的Maven报告
  6. c#完美截断字符串(中文+非中文)
  7. 关于提高自己Java水平十大技术
  8. 高考平行报志愿计算机录取规则,高考平行志愿录取规则是什么
  9. html实现返回上一页的几种方法(javaScript:history.go(-1);)
  10. [VNC] 云服务器 Ubuntu 16.04 安装 gnome 桌面并配置 VNC
  11. oracle 完整约束,【oracle】完整性約束
  12. python字符串_Python字符串
  13. 虚拟终端网络工程实施纪要
  14. 2022华为软件精英挑战赛——梯度方法
  15. 8月刚入职字节跳动的测试开发面试题,附答案
  16. Unity【HTC Vive Noitom】- 关于动作捕捉的两种解决方案
  17. linux鼠标手势双dock,Linnx Mint 上使用触摸板手势
  18. 《地球概论》(第3版)笔记 第二章 地球的宇宙环境
  19. ollydbg 教程
  20. 【以太网交换安全】---端口安全及MAC地址飘移防止与检测

热门文章

  1. 调试ASP程序时,遇到程序运行错误时怎么查看具体错误位置呢?
  2. IAR打开软件,很多文件找不到
  3. LaTex 希腊字母及特殊字符
  4. 剖析visa信用卡支付的交易处理流程
  5. SCQA结构化表达--提升沟通效果
  6. win11照片一打开就是打印怎么办?
  7. JavaScript学习过程
  8. 泛微OA发送内部邮件教程【E9版本】
  9. 【原创】解决JT2Go二次开发提示license key无效问题
  10. 非全日制计算机博士招生简章,非全日制教育博士招生简章2020