小码哥底层原理笔记:多线程
多线程方案:

比较常用的是GCD,是直接用Block去写代码的。使代码比较紧凑。
GCD常用函数
同步执行任务:dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
异步执行任务:dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
控制任务的执行顺序:
dispatch_barrier_async:栅栏函数,它等待所有位于barrier函数之前的操作执行完毕后执行,并且在barrier函数执行之后,barrier函数之后的操作才会得到执行。并且需要在异步并发队列才有效。
dipatch_group:线程组,可以实现A、B、C、任务并发执行,完了之后再通知执行D任务。
各种多线程队列的执行效果:

注意:全局队列也是一个并发队列,主队列是一个串行队列。同步和异步主要影响能不能开启新线程
多线程的安全隐患:当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题。
面试题
一
NSLog(@"执行任务1");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
NSLog(@"执行任务2");
});
NSLog(@"执行任务3");
以上代码在主线程中执行会产生死锁。dispatch_sync 会立马在当前线程执行任务
二
NSLog(@"执行任务1");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_async(queue, ^{
NSLog(@"执行任务2");
});
NSLog(@"执行任务3");
以上代码在主线程执行不会产生死锁。dispatch_async并不会立马执行。打印顺序是任务1、任务3、任务2。
三
NSLog(@"执行任务1");
dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{//block01
NSLog(@"执行任务2");
dispatch_sync(queue, ^{//block02
NSLog(@"执行任务3");
});
NSLog(@"执行任务4");
});
NSLog(@"执行任务5");
以上代码在主线程执行会产生死锁。会生成一个新线程,这个新线程是串行执行任务,先执行block01,然后再执行block02,由于block01在前面,要执行完block01才能执行block02,而block02又必须要等block01执行完,这样就互相等待,产生死锁。
四
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_async(queue, ^{
NSLog(@"1");
[self performSelector:@selector(test) withObject:nil afterDelay:0];
NSLog(@"3");
});
- (void)test{
NSLog(@"2");
}
以上代码只打印了1和3。因为performSelector:withObject:afterDelay方法的本质是往RunLoop里面添加了一个定时器。由于在这个子线程中没有启动RunLoop,所以test方法并不会执行。凡是有afterDelay的方法都是在RunLoop实现的。如果没有afterDelay比如performSelector:withObject:方法则是通过objc_msgSend执行。
死锁总结
使用sync同步执行往当前串行队列中添加任务,这样就会产生死锁