探索底层原理,积累从点滴做起。大家好,我是Mars。
往期回顾
iOS底层原理探索—OC对象的本质
iOS底层原理探索—class的本质
iOS底层原理探索—KVO的本质
iOS底层原理探索— KVC的本质
iOS底层原理探索— Category的本质(一)
iOS底层原理探索— Category的本质(二)
iOS底层原理探索— 关联对象的本质
iOS底层原理探索— block的本质(一)
iOS底层原理探索— block的本质(二)
iOS底层原理探索— Runtime之isa的本质
iOS底层原理探索— Runtime之class的本质
iOS底层原理探索— Runtime之消息机制
iOS底层原理探索—RunLoop的本质
iOS底层原理探索—RunLoop的应用
iOS底层原理探索—多线程的本质
前言
多线程是iOS
开发中很重要的一个环节,无论是开发过程还是在面试环节中,多线程出现的频率都非常高。我们会通过几篇文章的探索,深入浅出的分析多线程技术。
今天我们通过几道有关多线程的面试题,来帮助我们更加深入的了解多线程。
多线程的经典面试题
1、下面代码的执行结果是什么?
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
NSLog(@"任务1");
[self performSelector:@selector(test) withObject:nil afterDelay:1.0];
NSLog(@"任务3");
});
}
- (void)test {
NSLog(@"任务2");
}
答案是任务1,任务3
我们先分析一下代码:我们在全局队列dispatch_get_global_queue(0, 0)
中异步dispatch_async
执行三个任务。我们在iOS底层原理探索—多线程的本质一文中讲到,并发队列异步执行会开启子线程,说明三个任务都在子线程中执行,其中任务2是通过performSelector:withObject:afterDelay:
方法延迟1秒执行。那么为什么任务2没有打印呢?
原因就在于performSelector:withObject:afterDelay:
方法的本质是往RunLoop
中添加定时器,但是子线程默认情况下没有RunLoop
,需要手动创建,所以test
方法无法执行,任务2自然也不会打印。
下面我们手动为子线程开启RunLoop
测试一下:
可以看到,在启动
RunLoop
之后,任务2被执行,而且通过打印时间可以看出,任务2确实是在1秒后执行。
如果我们把performSelector:withObject:afterDelay:
方法替换成performSelector:withObject:
方法结果还会一样吗?
任务1,任务2,任务3直接打印了。
这是由于
performSelector:withObject:
方法的本质是通过消息机制
来调用的,所以能够执行任务2。我们可以通过performSelector:withObject:afterDelay:
方法的源码得到证明:2、下面代码的执行结果是什么?
- (void)viewDidLoad {
[super viewDidLoad];
NSThread *thread = [[NSThread alloc] initWithBlock:^{
NSLog(@"任务1");
}];
[thread start];
[self performSelector:@selector(test) onThread:thread withObject:nil waitUntilDone:YES];
}
- (void)test {
NSLog(@"任务2");
}
答案是打印完任务1,程序崩溃
我们在子线程thread
中执行任务1,等任务1执行完后再在子线程中执行test
方法。但是执行完任务1后,子线程thread
就被销毁了,所以接着要在子线程中执行test
方法时会崩溃。
当然,为子线程启动RunLoop
同样也可以解决程序崩溃的问题。大家可以测试一下。
队列组
队列组是用来管理队列中任务的执行,使用队列组异步函数来封装任务, 然后提交到队列中。队列组通过dispatch_group_notify
函数来监听任务执行。
我们通过下面一道题目来帮助理解队列组:
异步并发执行任务1、任务2,等任务1、任务2都执行完后回到主线程执行任务3
我们可以通过GCD的队列组来实现上面题目的要求:
通过打印我们看到,任务1和任务2在子线程中并发执行完后,回到主线程中执行任务3。
其中dispatch_group_notify
函数会在队列组dispatch_group_t
执行完队列组中的任务后接收到通知,来执行其他任务。