iOS開發多線程--線程安全

多線程的安全隱患

資源共享
一塊資源可能會被多個線程共享,也就是多個線程可能會訪問同一塊資源,比如多個線程訪問同一個對象、同一個變量、同一個文件,當多個線程訪問同一塊資源時,很容易引發數據錯亂和數據安全問題。
有問題的代碼:

@interface ViewController ()
 //剩余票數
@property(nonatomic,assign) int leftTicketsCount;
@property(nonatomic,strong)NSThread *thread1;
 @property(nonatomic,strong)NSThread *thread2;
 @property(nonatomic,strong)NSThread *thread3;
 @end
 @implementation ViewController
 - (void)viewDidLoad
 {
  [super viewDidLoad];
    //默認有20張票
    self.leftTicketsCount=10;
    //開啟多個線程,模擬售票員售票
    self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    self.thread1.name=@"售票員A";
    self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    self.thread2.name=@"售票員B";
    self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];
    self.thread3.name=@"售票員C";
}
- (void)sellTickets
 {
 while (1) {
 //1.先檢查票數
 int count=self.leftTicketsCount;
 if (count>0) {
     //暫停一段時間
  [NSThread sleepForTimeInterval:0.002];
  //2.票數-1
  self.leftTicketsCount= count-1;
   //獲取當前線程
  NSThread *current=[NSThread currentThread];
 NSLog(@"%@--賣了一張票,還剩余%d張票",current,self.leftTicketsCount);
 }else
   {
 //退出線程
          [NSThread exit];
      }
   }
 }
 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
 { 
  //開啟線程
 [self.thread1 start];
   [self.thread2 start];
    [self.thread3 start];
}
 @end

結果是數據錯亂:


1.png
  • 安全隱患分析:
2.png
3.png
  • 解決辦法,你需要加一把“鎖”,看代碼吧:
// 將上邊的錯誤代碼中的這個方法加以修改就好了就是加了一個@synchronized(self)
 -  (void)sellTickets
{
    while (1) {
     @synchronized(self){//只能加一把鎖

        //1.先檢查票數
        int count=self.leftTicketsCount;
        if (count>0) {
            //暫停一段時間
            [NSThread sleepForTimeInterval:0.002];
            //2.票數-1
            self.leftTicketsCount= count-1;
            //獲取當前線程
            NSThread *current=[NSThread currentThread];
            NSLog(@"%@--賣了一張票,還剩余%d張票",current,self.leftTicketsCount);
        }else
        {
            //退出線程
            [NSThread exit];
        }
    }
    }
}

其他代碼無需更改,再試下是不是就好了!保證每張票都是只被賣出一次。這個“鎖”就是保證數據不發生錯亂的根本保障。

  • 互斥鎖的優缺點
    優點:能有效防止因多線程搶奪資源造成的數據安全問題
    缺點:需要消耗大量的CPU資源
  • 互斥鎖的使用前提:多條線程搶奪同一塊資源
    相關專業術語:線程同步,多條線程按順序地執行任務
    互斥鎖,就是使用了線程同步技術

原子和非原子屬性

  • OC在定義屬性時有nonatomic和atomic兩種選擇
    atomic:原子屬性,為setter方法加鎖(默認就是atomic)
    nonatomic:非原子屬性,不會為setter方法加鎖
    atomic加鎖原理
 @property (assign, atomic) int age;
 - (void)setAge:(int)age
 { 
  @synchronized(self) { 
    _age = age;
 }
 }
  • 原子和非原子屬性的選擇
    nonatomic和atomic對比
    atomic:線程安全,需要消耗大量的資源
    nonatomic:非線程安全,適合內存小的移動設備

  • iOS開發的建議
    所有屬性都聲明為nonatomic
    盡量避免多線程搶奪同一塊資源
    盡量將加鎖、資源搶奪的業務邏輯交給服務器端處理,減小移動客戶端的壓力

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容