你好,歡迎來到IOS教程網

 Ios教程網 >> IOS訊息 >> 關於IOS >> NSThread使用詳解

NSThread使用詳解

編輯:關於IOS

1. NSThread相關的主要方法:

創建、啟動線程

[objc] view plaincopy

  1. NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
  2. [thread start];
  3. // 線程一啟動,就會在線程thread中執行self的run方法

 

主線程相關方法 + (NSThread *)mainThread; // 獲得主線程 [objc] view plaincopy

  1. - (BOOL)isMainThread; // 是否為主線程
  2. + (BOOL)isMainThread; // 是否為主線程

得到當前線程、獲取線程名字

[objc] view plaincopy

  1. NSThread *current = [NSThread currentThread];
  2. - (void)setName:(NSString *)name;
  3. - (NSString *)name;

創建線程後自動啟動線程

[objc] view plaincopy

  1. [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];

隱式創建並啟動線程

[objc] view plaincopy

  1. [self performSelectorInBackground:@selector(run) withObject:nil];

2. 線程狀態示意圖

3. 互斥鎖

@synchronized(鎖對象) { // 需要鎖定的代碼  }

注意:鎖定1份代碼只用1把鎖,用多把鎖是無效的

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

4. 原子性和非原子性

OC在定義屬性時有nonatomic和atomic兩種選擇 atomic:原子屬性,為setter方法加鎖(默認就是atomic) nonatomic:非原子屬性,不會為setter方法加鎖 atomic加鎖原理 [objc] view plaincopy

  1. @property (assign, atomic) int age;
  2. - (void)setAge:(int)age
  3. {
  4.     @synchronized(self) {
  5.         _age = age;
  6.     }
  7. }
nonatomic和atomic對比 atomic:線程安全,需要消耗大量的資源 nonatomic:非線程安全,適合內存小的移動設備 iOS開發的建議 所有屬性都聲明為nonatomic 盡量避免多線程搶奪同一塊資源 盡量將加鎖、資源搶奪的業務邏輯交給服務器端處理,減小移動客戶端的壓力

5. 線程間通信

什麼叫做線程間通信

在1個進程中,線程往往不是孤立存在的,多個線程之間需要經常進行通信 線程間通信的體現 1個線程傳遞數據給另1個線程 在1個線程中執行完特定任務後,轉到另1個線程繼續執行任務 線程間通信常用方法 [objc] view plaincopy

  1. - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
  2. - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait;

線程間通信示例 – 圖片下載

6. Demo 演示

業務描述(賣票): 模擬兩個線程搶奪一份資源

運行結果圖:

主要代碼說明:

1.  屬性及方法定義:

[objc] view plaincopy

  1. /* 
  2.     1. NSThread 可以使用NSLock 進行加鎖工作
  3.     2. NSOperation和GCD  應該使用同步鎖 :@synchronized(self),並且搶奪的內存資源應該定義為 atomic 的屬性
  4.  */
  5. @property (atomic,assign) int tickets;
  6. @property (atomic,strong) NSLock *lock;
  7. //  顯示結果區域
  8. @property (weak, nonatomic) IBOutlet UITextView *messageBoard;
  9. //  開始售票
  10. - (IBAction)threadSale;

2.  點擊Start對應方法的代碼:

[objc] view plaincopy

  1. - (IBAction)threadSale {
  2.     // 1. 先設定銷售票的數量
  3.     _tickets = 100;
  4.     // 創建線程1
  5.     NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSaleMethod) object:nil];
  6.     // 便於跟蹤時知道誰在工作
  7.     thread1.name = @"售票線程-1";
  8.     // 啟動線程
  9.     [thread1 start];
  10.     // 創建線程2
  11.     NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(threadSaleMethod) object:nil];
  12.     thread2.name = @"售票線程-2";
  13.     [thread2 start];
  14. }

3.  子線程執行內容對應的方法

[objc] view plaincopy

  1. - (void)threadSaleMethod {
  2.     // 1. 定義鎖,懶加載
  3.     if (_lock == nil) {
  4.         _lock = [[NSLock alloc] init];
  5.     }
  6.     while(YES)
  7.     {
  8.         [_lock lock];
  9.         if(_tickets > 0)
  10.         {
  11.             NSString *message = [NSString stringWithFormat:@"當前票數是%d,售票線程是%@",_tickets,[[NSThread currentThread] name]];
  12.             // 更新UI的工作,一定要放在主線程中完成
  13.             // waitUntilDone 的意思是:是否等待主線程更新完畢
  14.             [self performSelectorOnMainThread:@selector(appendTextView:) withObject:message waitUntilDone:YES];
  15.             _tickets--;
  16.             // 當前線程執行完畢,解鎖
  17.             [_lock unlock];
  18.             // 模擬延時
  19.             if ([[[NSThread currentThread] name] isEqualToString:@"售票線程-1"]) {
  20.                 [NSThread sleepForTimeInterval:0.2];
  21.             } else {
  22.                 [NSThread sleepForTimeInterval:0.3];
  23.             }
  24.         }
  25.         else{
  26.             // 在退出之前需要解鎖
  27.             [_lock unlock];
  28.             // 結束信息
  29.             NSString *str = [NSString stringWithFormat:@"票已售完%@", [[NSThread currentThread] name]];
  30.             [self performSelectorOnMainThread:@selector(appendTextView:) withObject:str waitUntilDone:YES];
  31.             break;
  32.         }
  33.     }
  34. }

4.  更新主線程UI對應的方法

[objc] view plaincopy

  1. - (void)appendTextView:(NSString *)text {
  2.     NSMutableString *str = [NSMutableString stringWithString:self.messageBoard.text];
  3.     [str appendFormat:@"n%@", text];
  4.     self.messageBoard.text = str;
  5.     // 用來將文本框滾動到想要的位置
  6.     // 我們現在想要滾動到最後,這個方法的參數是一個NSRange
  7.     NSRange range = NSMakeRange(str.length, 1);
  8.     [self.messageBoard scrollRangeToVisible:range];
  9. }

這一節,我詳細的介紹了線程的主要概念及NSThread的使用,下一節將為大家介紹GCD的概念及使用。

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved