- 共享資源:
一塊資源可能會被多個線程共享,也就是多個線程可能會訪問同一塊資源
比如多個線程訪問統(tǒng)一個對象年缎、同一個變量硅则、同一個文件
當(dāng)多個線程訪問同一塊資源時,很容易引發(fā)數(shù)據(jù)錯亂和數(shù)據(jù)安全問題
之所以會出現(xiàn)數(shù)據(jù)錯亂的問題,是由于CPU的工作特性,隨機(jī)在不同的線程間進(jìn)行調(diào)度.
先通過一段代碼演示多線程下訪問公共資源引發(fā)數(shù)據(jù)錯亂的情景:
#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
這段代碼中,兩條子線程分別訪問同一個成員變量并修改該成員變量的值,這里循環(huán)的次數(shù)比較少,如果想要出現(xiàn)數(shù)據(jù)錯亂線程更明顯一些,可以將循環(huán)次數(shù)變大,排除正常結(jié)果,在出現(xiàn)數(shù)據(jù)錯亂的情景中,有兩種典型的情況:
開始時先輸出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.假設(shè)藍(lán)色線程先被執(zhí)行,初始值10,進(jìn)入循環(huán)
2._totalCounts--; 藍(lán)色線程執(zhí)行自減,此時公共資源的值變?yōu)?
3.在執(zhí)行完自減,并在NSLog輸出前,該線程進(jìn)入阻塞狀態(tài),CPU切換到粉色線程執(zhí)行任務(wù)
4.粉色線程初始值9,進(jìn)入循環(huán)
5._totalCounts--; 粉色線程同樣執(zhí)行自減,此時公共資源的值變?yōu)?
6.粉色線程繼續(xù)執(zhí)行NSLog,輸出結(jié)果8,粉色線程進(jìn)入阻塞狀態(tài)
7.再次切換回藍(lán)色線程執(zhí)行下一句代碼NSLog,之前記錄的結(jié)果為9,所以打印結(jié)果為9
從而出現(xiàn)先打印8,后打印9的現(xiàn)象
開始時連續(xù)輸出兩個9
這種情況模擬時出現(xiàn)的概率比較低,直接分析結(jié)果:
1.假設(shè)藍(lán)色線程先被執(zhí)行,初始值10,進(jìn)入循環(huán)
2.在執(zhí)行自減操作前藍(lán)色線程就進(jìn)入阻塞狀態(tài),此時公共資源的值仍為10
3.CPU切換到粉色線程執(zhí)行任務(wù),粉色線程初始值10,進(jìn)入循環(huán)
4._totalCounts--; 粉色線程執(zhí)行自減,此時公共資源的值變?yōu)?
5.粉色線程繼續(xù)執(zhí)行NSLog,輸出結(jié)果9,粉色線程進(jìn)入阻塞狀態(tài)
6.再次切換回藍(lán)色線程,根據(jù)上一次操作記錄(初始值10,滿足條件進(jìn)入循環(huán))繼續(xù)執(zhí)行任務(wù),執(zhí)行自減操作,此時totalCounts由10變?yōu)?
7.執(zhí)行NSLog,打印結(jié)果為9
從而導(dǎo)致出現(xiàn)開始連續(xù)兩次打印9 的現(xiàn)象
正因為CPU的這種工作特性,如果使用多線程,不對公共資源做處理,就會造成數(shù)據(jù)安全問題,除了上述的兩種典型情況外,還有其他情況,例如:
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] 停止