为了方便测试,我们写一个耗时计算的方法:
-(void)calculateAction{
// 当子线程中出现对象类型时,需要使用自动释放池包裹对应的代码
@autoreleasepool {
int sum = 0;
for (int i =0; i<655350000; i++) {
sum += i;
}
// 打印当前方法是否为主线程
NSLog(@"===当前线程A:%d",[NSThread isMainThread]);
// 打印当前线程
NSLog(@"===当前线程B:%@",[NSThread currentThread]);
NSLog(@"===结果:%d",sum);
}
}
1、NSThread
NSThread的创建:
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(calculateAction) object:nil];
[thread start];
NSLog(@"===当前线程%d",[NSThread isMainThread]);
NSLog(@"===当前线程11:%@",[NSThread currentThread]);
[thread cancel];
这里,我们可以看到输出的结果是:耗时计算的方法是在子线程中执行。
同时,NSThread还包含isExecuting、isCancelled属性,是否在执行,是否取消执行。NSThread需要手动开启。
[NSThread sleepForTimeInterval:10];关于这个方法的用处,在融云SDK里发送多张图片中用到过,在for循环中,加入延时执行代码,在发送效果上给人感觉是动态的,而不是直接生硬的瞬间出现多张图片的发送。
由于耗时计算是在子线程当中,当子线程中完成操作后,我们要回到主线程中去执行下一步操作,这里有两种回到主线程的方式:
1️⃣参数的意义:1、执行在主线程的方法 2、传递的参数 3、是否等待完成后操作
[self performSelectorOnMainThread:@selector(mainAction:) withObject:@(sum) waitUntilDone:YES];
-(void)mainAction:(NSNumber *)sum{
NSLog(@"计算的结果%d",[sum intValue]);
NSLog(@"当前线程是否为主线程:%d",[NSThread isMainThread]);
}
打印结果:
2️⃣
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"===计算的结果%d",sum);
NSLog(@"===当前线程是否为主线程:%d",[NSThread isMainThread]);
});
静态方法直接开辟子线程:
[NSThread detachNewThreadSelector:@selector(calculateAction) toTarget:self withObject:nil];
2、NSObject
[self performSelectorInBackground:@selector(calculateAction) withObject:nil];
3、NSOperationQuene
NSOperationQuene:此种多线程方式和NSOperation的两个子类来结合使用实现多线程方式
// 3.1
NSInvocationOperation *invocation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(calculateAction) object:nil];
// 3.2
NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{
[self test];
}];
// 创建管理队列的两个任务
NSOperationQueue *queue = [NSOperationQueue new];
// 设置最大并发数(同时执行的任务个数)
// 若最大并发数设置为1.那么任务按照串行方式执行(1就是跟串联一样)
[queue setMaxConcurrentOperationCount:2];
// 将任务添加到队列
[queue addOperation:invocation];
[queue addOperation:block];
一个检测先后顺序的test方法
-(void)test{
NSLog(@"测试的时间。。。。");
}
那么,最后输出的结果是:
可以得出的结论是:队列中先加入谁就先执行谁,但是不代表先执行的方法就先结束。
4、GCD
两种队列方式:并行队列,串行队列
并行队列:所有任务并发执行,不分先后
串行队列:所有任务一次执行,排队完成
GCD中,有三种队列可以使用
主队列:系统提供的单例,属于串行队列
全局队列:系统提供的单例,属于并行队列
自定义队列:开发人员可以自定义选择使用串行或并行
主队列
输出结果是:为顺序执行的串行队列
全局队列:并行队列(也遵循FIFO,先进先出原则)---会开辟子线程,但是其管理的任务不一定只在子线程执行,也会添加到主线程执行
// 1、队列优先级
// 2、空余参数,以后添加作用
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 必须先执行的代码(第一个加入队列时,才会优先执行此任务)
dispatch_barrier_sync(globalQueue, ^{
NSLog(@"优先执行的代码");
});
dispatch_async(globalQueue, ^{
NSLog(@"第一个任务:%d",[NSThread isMainThread]);
});
dispatch_async(globalQueue, ^{
NSLog(@"第二个任务:%d",[NSThread isMainThread]);
});
dispatch_async(globalQueue, ^{
NSLog(@"第三个任务:%d",[NSThread isMainThread]);
});
// 延时启动任务
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), globalQueue, ^{
NSLog(@"出来吧,神龙!");
});
// 反复执行n次的任务
dispatch_apply(3, globalQueue, ^(size_t time) {
NSLog(@"第%zu次",time);
});
// 添加函数
// 参数:1、要把任务添加到的队列 2、函数的参数 3、函数
dispatch_async_f(globalQueue, "I love my iOS teacher", function);
// 函数
void function(void * string);
void function(void * string){
NSLog(@"%s",string);
}
输出结果:
由此可以看出,第一到第三个任务并不是顺序执行的。为并行执行。
自定义队列
串行
当全部为sync时,线程顺序执行,优先在当前线程中执行,打印结果是:
当为async时,线程并行执行
并行队列,当前线程为并行执行,且在用async,即异步的时候,是在子线程中执行
串行但异步执行
并行但异步执行
分组:异步执行
对线程的一些小总结,很简单,后续进行深入补充。