- 共享資源:
一塊資源可能會被多個線程共享,也就是多個線程可能會訪問同一塊資源
比如多個線程訪問統一個對象、同一個變量、同一個文件
當多個線程訪問同一塊資源時,很容易引發數據錯亂和數據安全問題
之所以會出現數據錯亂的問題,是由于CPU的工作特性,隨機在不同的線程間進行調度.
先通過一段代碼演示多線程下訪問公共資源引發數據錯亂的情景:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController{
NSInteger _totalCounts;
}
- (void)viewDidLoad {
[super viewDidLoad];
_totalCounts = 10;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSThread *thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
[thread1 start];
[thread2 start];
}
- (void)demo{
for (int i = 0; i < 10 ;i ++) {
if (_totalCounts > 0) {
_totalCounts--;
NSLog(@"%zd",_totalCounts);
}else{
NSLog(@"停止");
break;
}
}
}
@end
這段代碼中,兩條子線程分別訪問同一個成員變量并修改該成員變量的值,這里循環的次數比較少,如果想要出現數據錯亂線程更明顯一些,可以將循環次數變大,排除正常結果,在出現數據錯亂的情景中,有兩種典型的情況:
開始時先輸出8,后輸出9
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253147] 8
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253148] 9
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253147] 7
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253148] 6
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253147] 5
2016-07-30 22:35:26.863 多線程訪問共享資源[1580:253148] 4
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253147] 3
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253148] 2
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253147] 1
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253148] 0
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253147] 停止
2016-07-30 22:35:26.864 多線程訪問共享資源[1580:253148] 停止
分析:
1.假設藍色線程先被執行,初始值10,進入循環
2._totalCounts--; 藍色線程執行自減,此時公共資源的值變為9
3.在執行完自減,并在NSLog輸出前,該線程進入阻塞狀態,CPU切換到粉色線程執行任務
4.粉色線程初始值9,進入循環
5._totalCounts--; 粉色線程同樣執行自減,此時公共資源的值變為8
6.粉色線程繼續執行NSLog,輸出結果8,粉色線程進入阻塞狀態
7.再次切換回藍色線程執行下一句代碼NSLog,之前記錄的結果為9,所以打印結果為9
從而出現先打印8,后打印9的現象
開始時連續輸出兩個9
這種情況模擬時出現的概率比較低,直接分析結果:
1.假設藍色線程先被執行,初始值10,進入循環
2.在執行自減操作前藍色線程就進入阻塞狀態,此時公共資源的值仍為10
3.CPU切換到粉色線程執行任務,粉色線程初始值10,進入循環
4._totalCounts--; 粉色線程執行自減,此時公共資源的值變為9
5.粉色線程繼續執行NSLog,輸出結果9,粉色線程進入阻塞狀態
6.再次切換回藍色線程,根據上一次操作記錄(初始值10,滿足條件進入循環)繼續執行任務,執行自減操作,此時totalCounts由10變為9
7.執行NSLog,打印結果為9
從而導致出現開始連續兩次打印9 的現象
正因為CPU的這種工作特性,如果使用多線程,不對公共資源做處理,就會造成數據安全問題,除了上述的兩種典型情況外,還有其他情況,例如:
2016-07-30 23:16:04.960 多線程訪問共享資源[1725:297008] 8
2016-07-30 23:16:04.960 多線程訪問共享資源[1725:297009] 9
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297008] 7
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297009] 6
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297008] 5
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297009] 4
2016-07-30 23:16:04.961 多線程訪問共享資源[1725:297008] 3
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297009] 2
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297008] 1
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297008] 停止
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297009] 0
2016-07-30 23:16:04.962 多線程訪問共享資源[1725:297009] 停止