一般来说,多线程编程因具有以下几个优点,一直被广泛应用:
- 资源利用率更好
- 程序设计在某些情况下更简单
- 程序响应更快
但是因为多线程而导致的crash问题,也是令程序员非常头疼的一个问题,因为线程调度执行顺序的不确定性,造成了crash一般都是小概率出现,在开发测试阶段很难发现,而一旦上线面对用户,造成的影响却是不容小觑的。
一、Crash的场景
有一种特别常见的会造成crash的场景为:多线程读写可变数组/字典
我们来看几个简单的测试代码,看看到底在什么情况下会引起Crash:
// 1. 多线程只读数据
NSMutableDictionary * dict1 = [[NSMutableDictionary alloc] init];
[dict1 setObject:@"test0" forKey:@"test0"];
[dict1 setObject:@"test1" forKey:@"test1"];
[dict1 setObject:@"test2" forKey:@"test2"];
for (int i = 0; i < 1000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSString * key = [NSString stringWithFormat:@"test%d", i%3];
NSString * value = dict1[key];
NSLog(@"%@:%@", key, value);
});
}
// 2. 多线程只写数据
// 字典仅有一个key
// 多线程写同一个key
NSMutableDictionary * dict2 = [[NSMutableDictionary alloc] init];
for (int i = 0; i < 1000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[dict2 setObject:@(i) forKey:@"test"];
});
}
// 3. 多线程只写数据
// 字典有多个key
// 多线程同时写不同key
NSMutableDictionary * dict3 = [[NSMutableDictionary alloc] init];
for (int i = 0; i < 1000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[dict3 setObject:[NSString stringWithFormat:@"test%d", i] forKey:[NSString stringWithFormat:@"test%d", i]];
});
}
// 4. 多线程只写数据
// 字典有多个key
// 多线程随机写key
NSMutableDictionary * dict4 = [[NSMutableDictionary alloc] init];
for (int i = 0; i < 1000; i++) {
int x = arc4random() % 3;
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[dict4 setObject:[NSString stringWithFormat:@"test%d", i] forKey:[NSString stringWithFo