1、多線程的安全隱患安全
資源共享服務器
1塊資源可能會被多個線程共享,也就是多個線程可能會訪問同一塊資源多線程
好比多個線程訪問同一個對象、同一個變量、同一個文件app
當多個線程訪問同一塊資源時,很容易引起數據錯亂和數據安全問題atom
示例一:spa
示例二:線程
問題代碼:3d
1 // 2 // YYViewController.m 3 // 05-線程安全 4 // 5 // Created by apple on 14-6-23. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 10 #import "YYViewController.h" 11 12 @interface YYViewController () 13 //剩餘票數 14 15 @property(nonatomic,assign) int leftTicketsCount; 16 @property(nonatomic,strong)NSThread *thread1; 17 @property(nonatomic,strong)NSThread *thread2; 18 @property(nonatomic,strong)NSThread *thread3; 19 20 21 @end 22 23 24 @implementation YYViewController 25 26 27 - (void)viewDidLoad 28 { 29 [super viewDidLoad]; 30 31 //默認有20張票 32 33 self.leftTicketsCount=10; 34 35 //開啓多個線程,模擬售票員售票 36 37 self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil]; 38 39 self.thread1.name=@"售票員A"; 40 41 self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil]; 42 43 self.thread2.name=@"售票員B"; 44 45 self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil]; 46 self.thread3.name=@"售票員C"; 47 } 48 49 50 -(void)sellTickets 51 { 52 while (1) { 53 //1.先檢查票數 54 int count=self.leftTicketsCount; 55 if (count>0) { 56 //暫停一段時間 57 [NSThread sleepForTimeInterval:0.002]; 58 59 //2.票數-1 60 self.leftTicketsCount= count-1; 61 62 //獲取當前線程 63 NSThread *current=[NSThread currentThread]; 64 NSLog(@"%@--賣了一張票,還剩餘%d張票",current,self.leftTicketsCount); 65 }else 66 { 67 //退出線程 68 [NSThread exit]; 69 } 70 } 71 } 72 73 74 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 75 { 76 //開啓線程 77 78 [self.thread1 start]; 79 [self.thread2 start]; 80 [self.thread3 start]; 81 82 } 83 84 @end
打印結果:code
2、安全隱患分析對象
3、如何解決
互斥鎖使用格式
@synchronized(鎖對象) { // 須要鎖定的代碼 }
注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的
代碼示例:
1 // 2 // YYViewController.m 3 // 05-線程安全 4 // 5 // Created by apple on 14-6-23. 6 // Copyright (c) 2014年 itcase. All rights reserved. 7 // 8 9 #import "YYViewController.h" 10 11 @interface YYViewController () 12 13 //剩餘票數 14 @property(nonatomic,assign) int leftTicketsCount; 15 @property(nonatomic,strong)NSThread *thread1; 16 @property(nonatomic,strong)NSThread *thread2; 17 @property(nonatomic,strong)NSThread *thread3; 18 @end 19 20 @implementation YYViewController 21 22 - (void)viewDidLoad 23 { 24 [super viewDidLoad]; 25 //默認有20張票 26 self.leftTicketsCount=10; 27 //開啓多個線程,模擬售票員售票 28 29 self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil]; 30 31 self.thread1.name=@"售票員A"; 32 33 self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil]; 34 35 self.thread2.name=@"售票員B"; 36 37 self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil]; 38 39 self.thread3.name=@"售票員C"; 40 } 41 42 43 -(void)sellTickets 44 { 45 while (1) { 46 @synchronized(self){//只能加一把鎖 47 //1.先檢查票數 48 49 int count=self.leftTicketsCount; 50 if (count>0) { 51 //暫停一段時間 52 [NSThread sleepForTimeInterval:0.002]; 53 //2.票數-1 54 55 self.leftTicketsCount= count-1; 56 //獲取當前線程 57 NSThread *current=[NSThread currentThread]; 58 NSLog(@"%@--賣了一張票,還剩餘%d張票",current,self.leftTicketsCount); 59 60 }else 61 { 62 //退出線程 63 [NSThread exit]; 64 } 65 } 66 } 67 } 68 69 70 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 71 { 72 73 //開啓線程 74 [self.thread1 start]; 75 [self.thread2 start]; 76 [self.thread3 start]; 77 } 78 79 @end
執行效果圖
互斥鎖的優缺點
優勢:能有效防止因多線程搶奪資源形成的數據安全問題
缺點:須要消耗大量的CPU資源
互斥鎖的使用前提:多條線程搶奪同一塊資源
相關專業術語:線程同步,多條線程按順序地執行任務
互斥鎖,就是使用了線程同步技術
四:原子和非原子屬性
OC在定義屬性時有nonatomic和atomic兩種選擇
atomic:原子屬性,爲setter方法加鎖(默認就是atomic)
nonatomic:非原子屬性,不會爲setter方法加鎖
atomic加鎖原理
1 @property (assign, atomic) int age; 2 3 - (void)setAge:(int)age 4 { 5 6 @synchronized(self) { 7 _age = age; 8 } 9 }
原子和非原子屬性的選擇
nonatomic和atomic對比
atomic:線程安全,須要消耗大量的資源
nonatomic:非線程安全,適合內存小的移動設備
iOS開發的建議
全部屬性都聲明爲nonatomic
儘可能避免多線程搶奪同一塊資源
儘可能將加鎖、資源搶奪的業務邏輯交給服務器端處理,減少移動客戶端的壓力