本文是笔者通过前辈的指导,然后总结一些 IOS 多线程的注意点,总结的知识点不会太全面,希望读者们多多谅解。本文不会涉及到多线程三个工具的用法--- NSThread 、 GCD 、 NSOperation 。
NSThread
NSThread 相比 GCD 和 NSOperation ,其优点是更为轻量级的;
缺点就是需要自己去管理线程的生命周期,线程同步,为了避免多个线程访问并修改同一资源,还要加上互斥锁(性能消耗很大)。
所谓的轻量级,其实是指其代码库小,实现的功能少,但并不代表着性能消耗小,这是一个注意点。
<br />
少调用 NSThread 的 exit 方法
引用苹果官方文档的一句话
Invoking this method should be avoided as it does not give your thread a chance to clean up any resources it allocated during its execution.
翻译:应避免调用此方法,因为它不会让线程有机会清除其执行期间分配的任何资源。
前辈大佬给我举了个例子:如果线程正在执行文件操作,在没有关闭文件之前调用该方法,线程的入口函数就会立即被清空(可以理解为马上停止在线程中的操作,退出当前线程),文件没有关闭,导致内存崩溃。
<br />
NSThread 的 sleepUntilDate: 和 RunLoop 的 runUntilDate: 的区别
- NSThread 的 sleepUntilDate: 线程在睡眠期间,任何事情都唤醒不了该线程,直到 Date 结束了,才会唤醒线程。
- RunLoop 的 runUntilDate: runLoop 在睡眠期间,是有可能被其他事情唤醒的。
<br />
GCD
相比于 NSThread ,GCD 不需要我们去管理线程的生命周期,我们只是简单地往线程中添加操作就可以了,其他的事情 GCD 都会帮我们实行。
<br />
GCD 出现死锁的情况
-(void)text{
NSLog(@"1");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"2");
});
NSLog(@"3");
}
上面的情况就是串行队列里面同步提交当前串行队列导致死锁。
这个问题经过大佬的讲解,笔者一下子就通了。
解释: dispatch_sync
同步函数是要等 Block 里面的内容执行完才会返回的。
上面的代码的执行顺序 : 输出1 --> dispatch_sync --> 输出3
执行到同步函数的时候,就会把 Block 追加的 3 的后面,即:
dispatch_sync --> 输出3 --> 输出2
上面构成的循环等待如下:
dispatch_sync 等待 输出2 (上面提到同步函数的特性)
输出2 等待 输出3
输出3 等待 dispatch_sync
即使没有输出3的这一步操作,还是有可能造成死锁,因为在主线程中有很多事情要做,所以难免会有其他事件像输出3那样插入在输出2之前,然后造成死锁。
<br />
dispatch_after
dispatch_after
是延迟执行,这个的注意点在意延迟这个概念,不是延迟这行 Block 的代码(即执行线程中的操作),而是延迟**把Block 提交到队列当中 **,这个概念一定要注意。