iOS —— 多線程應用,ios多線程應用

來源:互聯網
上載者:User

iOS —— 多線程應用,ios多線程應用
一、共用資源

共用資源 : 就是記憶體中的一塊資源同時被多個進程所訪問,而每個進程可能會對該資源的資料進行修改

問題 : 如果 線程A 訪問了某塊資源 C,並且修改了其中的資料,此時 線程B 也訪問了 資源C,並且也對 C 中的資料進行了修改;那麼等到 線程A 和 線程B 執行結束後,此時,資源C 中的資料就並不是最初的設定了

 

 

此時,如果使用者想擷取 被 線程A 修改的 資源C 的資料,但是 資源C 的資料也被 線程B 修改了,所以獲得的是錯誤的資料;如果使用者想擷取 被 線程B 修改的 資源C 的資料,但是 資源C 的資料也被 線程A 修改了,所以獲得的是錯誤的資料

 

下面看代碼,以出售火車票為例

建立火車票資料模型

 

 1 // LHTicketModal.h 2 #import <Foundation/Foundation.h> 3  4 @interface LHTicketModal : NSObject 5  6 @property (nonatomic) NSUInteger ticketCount;       // 剩餘票數 7 @property (nonatomic) NSUInteger ticketSaleCount;   // 賣出數量 8  9 @end10 11 // LHTicketModal.m12 #import "LHTicketModal.h"13 14 static const NSUInteger kTicketTotalCount = 50;15 16 @implementation LHTicketModal17 18 - (instancetype)init {19 20     self = [super init];21     22     if (self) {23     24         // 初始化剩餘票數應該為總數25         _ticketCount = kTicketTotalCount;26         27         // 初始化賣出票數應該為 028         _ticketSaleCount = 0;29     30     }31     32     return self;33 34 }35 36 @end

 

 

UIViewController 代碼

 1 // LHSharedViewController.h 2 #import "LHSharedViewController.h" 3 #import "LHTicketModal.h" 4  5 @interface LHSharedViewController () 6  7 // 車票模型 8 @property (nonatomic, strong) LHTicketModal * ticket; 9 10 // 線程對象11 @property (nonatomic, strong) NSThread * threadBJ;12 @property (nonatomic, strong) NSThread * threadSH;13 14 @end15 16 // LHSharedViewController.m17 @implementation LHSharedViewController18 19 - (void)viewDidLoad {20     21     [super viewDidLoad];22     23     // 1. 初始化 票數模型對象24     _ticket = [[LHTicketModal alloc] init];25     26     // 2. 初始化 線程對象 並設定線程名27     _threadBJ = [[NSThread alloc] initWithTarget:self selector:@selector(sellTickets:) object:@"北京賣出"];28     29     _threadBJ.name = @"北京";30     31     _threadSH = [[NSThread alloc] initWithTarget:self selector:@selector(sellTickets:) object:@"上海賣出"];32     33     _threadSH.name = @"上海";34 35 }36 37 // 線程執行的方法38 - (void)sellTickets:(NSString *)str {39 40     while (YES) {41     42         // 判斷剩餘量是否大於 0,大於 0 才可以賣出43         if (_ticket.ticketCount > 0) {44         45             // 暫停一段時間46             [NSThread sleepForTimeInterval:0.2];47             48             // 賣出一張票,剩餘票數減 1,賣出票數加 149             _ticket.ticketCount--;50             51             _ticket.ticketSaleCount++;52             53             // 擷取當前進程54             NSThread * currentThread = [NSThread currentThread];55             56             NSLog(@"%@ 賣了一張票,還剩 %lu 張票", currentThread.name, _ticket.ticketCount);57             58         }59     60     }61 62 }63 64 // 按鈕的動作方法65 - (IBAction)startSaleBtnClick:(id)sender {66     67     // 開啟線程68     [_threadBJ start];69     70     [_threadSH start];71     72     73 }

點擊按鈕後,線程開始運行,結果

 

看一看出,共用資源同時被多個線程訪問並修改,導致使用者取得了錯誤的資料

 

那麼解決這種情況的辦法就是 加鎖

加鎖是指對一段代碼進行加鎖,加鎖之後,若一個線程已經在對共用資源的資料修改,此時就不會再有其他線程來訪問該資源進行修改,直至當前線程已經結束修改資源的代碼時,其他進程才可以對其進行修改

可以把共用資源看做一個房間,線程看做人;當一個人進入房間之後就會鎖門(加鎖),對房間進行各種布置,此時其他人是進不來的,因為沒有鑰匙;直至當前的人出房間,其他的人才可以進房間進行布置

 

加鎖的方式有多種,這裡介紹兩種

方式一 : 使用  @synchronized (加鎖對象) {} 關鍵字

只需修改上述代碼的  sellTickets 方法,其餘不變,這裡將其方法名改為  sellTickets_v2

 1 - (void)sellTickets_v2:(NSString *)str { 2      3     while (YES) { 4          5         // 對當前對象加鎖 6         @synchronized (self) { 7              8             // 判斷剩餘量是否大於 0,大於 0 才可以賣出 9             if (_ticket.ticketCount > 0) {10             11                 // 暫停一段時間12                 [NSThread sleepForTimeInterval:0.2];13             14                 // 賣出一張票,剩餘票數減 1,賣出票數加 115                 _ticket.ticketCount--;16             17                 _ticket.ticketSaleCount++;18             19                 // 擷取當前進程20                 NSThread * currentThread = [NSThread currentThread];21             22                 NSLog(@"%@ 賣了一張票,還剩 %lu 張票", currentThread.name, _ticket.ticketCount);23             24             }25             26         }27         28     }29     30 }

再次運行程式,點擊按鈕。結果

 

 

方式二 : 使用 NSCondition 類

在 類擴充中聲明並在 viewDidLoad 方法中初始化

 

 1 - (void)sellTickets_v3:(NSString *)str { 2      3     while (YES) { 4          5         // 使用 NSCondition 加鎖 6         [_ticketCondition lock]; 7          8         // 判斷剩餘量是否大於 0,大於 0 才可以賣出 9         if (_ticket.ticketCount > 0) {10                 11             // 暫停一段時間12             [NSThread sleepForTimeInterval:0.2];13                 14             // 賣出一張票,剩餘票數減 1,賣出票數加 115             _ticket.ticketCount--;16                 17             _ticket.ticketSaleCount++;18                 19             // 擷取當前進程20             NSThread * currentThread = [NSThread currentThread];21                 22             NSLog(@"%@ 賣了一張票,還剩 %lu 張票", currentThread.name, _ticket.ticketCount);23             24         }25         26         // 使用 NSCondition 解鎖27         [_ticketCondition unlock];28         29     }30     31 }

 

運行結果和上述一樣

使用 NSCondition 時,將加鎖的代碼放在 loac 和 unlock 中間

 

總結 :

  1. 互斥鎖的優缺點

    優點 : 有效防止因多線程搶奪資源造成的資料安全問題

    缺點 : 需要消耗大量 CPU 資源

 

  2. 互斥鎖使用的前提

    多個線程搶奪同一資源

    線程同步,互斥鎖就是使用了線程同步  

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.