標籤:
原文 http://www.cnblogs.com/wendingding/p/3805841.html
iOS開發多線程篇—安全執行緒
一、多線程的安全隱患
資源共用
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 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 @end22 23 24 @implementation YYViewController25 26 27 - (void)viewDidLoad28 {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 [email protected]"售票員A";40 41 self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];42 43 [email protected]"售票員B";44 45 self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];46 [email protected]"售票員C";47 }48 49 50 -(void)sellTickets51 {52 while (1) {53 //1.先檢查票數54 int count=self.leftTicketsCount;55 if (count>0) {56 //暫停一段時間57 [NSThread sleepForTimeInterval:0.002];58 59 //2.票數-160 self.leftTicketsCount= count-1;61 62 //擷取當前線程63 NSThread *current=[NSThread currentThread];64 NSLog(@"%@--賣了一張票,還剩餘%d張票",current,self.leftTicketsCount);65 }else66 {67 //退出線程68 [NSThread exit];69 }70 }71 }72 73 74 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event75 { 76 //開啟線程77 78 [self.thread1 start];79 [self.thread2 start];80 [self.thread3 start];81 82 }83 84 @end
列印結果:
二、安全隱患分析
三、如何解決
互斥鎖使用格式
@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 @end19 20 @implementation YYViewController21 22 - (void)viewDidLoad23 {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 [email protected]"售票員A";32 33 self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];34 35 [email protected]"售票員B";36 37 self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];38 39 [email protected]"售票員C";40 }41 42 43 -(void)sellTickets44 {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.票數-154 55 self.leftTicketsCount= count-1;56 //擷取當前線程57 NSThread *current=[NSThread currentThread];58 NSLog(@"%@--賣了一張票,還剩餘%d張票",current,self.leftTicketsCount);59 60 }else61 {62 //退出線程63 [NSThread exit];64 }65 }66 }67 }68 69 70 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event71 {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)age4 { 5 6 @synchronized(self) { 7 _age = age;8 }9 }
原子和非原子屬性的選擇
nonatomic 和 atomic 對比
atomic : 安全執行緒,需要消耗大量的資源
nonatomic : 非安全執行緒,適合記憶體小的行動裝置
iOS 開發的建議
所有屬性都聲明為 nonatomic
盡量避免多線程搶奪同一塊資源
盡量將加鎖、資源搶奪的商務邏輯交給伺服器端處理,減小移動用戶端的壓力
iOS開發多線程篇-GCD介紹