自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iOS多線程篇:NSThread

移動開發(fā)
NSThread是基于線程使用,輕量級的多線程編程方法(相對GCD和NSOperation),一個NSThread對象代表一個線程,需要手動管理線程的生命周期,處理線程同步等問題。

[[165210]]

一、什么是NSThread

NSThread是基于線程使用,輕量級的多線程編程方法(相對GCD和NSOperation),一個NSThread對象代表一個線程,需要手動管理線程的生命周期,處理線程同步等問題。

二、NSThread方法介紹

1)動態(tài)創(chuàng)建

 

  1. NSThread * newThread = [[NSThread alloc]initWithTarget:self selector:@selector(threadRun) object:nil]; 

 

動態(tài)方法返回一個新的thread對象,需要調(diào)用start方法來啟動線程

2)靜態(tài)創(chuàng)建

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

由于靜態(tài)方法沒有返回值,如果需要獲取新創(chuàng)建的thread,需要在selector中調(diào)用獲取當前線程的方法

3)線程開啟

  1. [newThread start]; 

4)線程暫停

  1. [NSThread sleepForTimeInterval:1.0]; (以暫停一秒為例) 
  2. [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; 

NSThread的暫停會有阻塞當前線程的效果

5)線程取消

  1. [newThread cancel]; 

取消線程并不會馬上停止并退出線程,僅僅只作(線程是否需要退出)狀態(tài)記錄

6)線程停止

  1. [NSThread exit]; 

停止方法會立即終止除主線程以外所有線程(無論是否在執(zhí)行任務(wù))并退出,需要在掌控所有線程狀態(tài)的情況下調(diào)用此方法,否則可能會導(dǎo)致內(nèi)存問題。

7)獲取當前線程

  1. [NSThread currentThread]; 

8)獲取主線程

 

  1. [NSThread mainThread]; 

 

9)線程優(yōu)先級設(shè)置

iOS8以前使用

  1. [NSThread setThreadPriority:1.0]; 

這個方法的優(yōu)先級的數(shù)值設(shè)置讓人困惑,因為你不知道你應(yīng)該設(shè)置多大的值是比較合適的,因此在iOS8之后,threadPriority添加了一句注釋:To be deprecated; use qualityOfService below

意思就是iOS8以后推薦使用qualityOfService屬性,通過量化的優(yōu)先級枚舉值來設(shè)置
qualityOfService的枚舉值如下:
NSQualityOfServiceUserInteractive:***優(yōu)先級,用于用戶交互事件
NSQualityOfServiceUserInitiated:次高優(yōu)先級,用于用戶需要馬上執(zhí)行的事件
NSQualityOfServiceDefault:默認優(yōu)先級,主線程和沒有設(shè)置優(yōu)先級的線程都默認為這個優(yōu)先級
NSQualityOfServiceUtility:普通優(yōu)先級,用于普通任務(wù)
NSQualityOfServiceBackground:***優(yōu)先級,用于不重要的任務(wù)

比如給線程設(shè)置次高優(yōu)先級:

  1. [newThread setQualityOfService:NSQualityOfServiceUserInitiated]; 

三、線程間通信

常用的有三種:

  1、指定當前線程執(zhí)行操作

  1. [self performSelector:@selector(threadRun)]; 
  2. [self performSelector:@selector(threadRun) withObject:nil]; 
  3. [self performSelector:@selector(threadRun) withObject:nil afterDelay:2.0]; 

  2、(在其他線程中)指定主線程執(zhí)行操作

  1. [self performSelectorOnMainThread:@selector(threadRun) withObject:nil waitUntilDone:YES]; 

注意:更新UI要在主線程中進行

  3、(在主線程中)指定其他線程執(zhí)行操作

  1. [self performSelector:@selector(threadRun) onThread:newThread withObject:nil waitUntilDone:YES]; //這里指定為某個線程 
  2. [self performSelectorInBackground:@selector(threadRun) withObject:nil];//這里指定為后臺線程 

四、線程同步

線程和其他線程可能會共享一些資源,當多個線程同時讀寫同一份共享資源的時候,可能會引起沖突。線程同步是指是指在一定的時間內(nèi)只允許某一個線程訪問某個資源

iOS實現(xiàn)線程加鎖有NSLock和@synchronized兩種方式

五、線程的創(chuàng)建和使用實例:模擬售票

情景:某演唱會門票發(fā)售,在廣州和北京均開設(shè)窗口進行銷售,以下是代碼實現(xiàn)

  1. 先監(jiān)聽線程退出的通知,以便知道線程什么時候退出 
  2. [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(threadExitNotice) name:NSThreadWillExitNotification object:nil]; 
 
  1. 設(shè)置演唱會的門票數(shù)量 
  2.      _ticketCount = 50
  1. 新建兩個子線程(代表兩個窗口同時銷售門票) 
  2.      NSThread * window1 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil]; 
  3.      window1.name = @"北京售票窗口"; 
  4.      [window1 start]; 
  5.  
  6.      NSThread * window2 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil]; 
  7.      window2.name = @"廣州售票窗口"; 
  8.      [window2 start]; 
  1. 線程啟動后,執(zhí)行saleTicket,執(zhí)行完畢后就會退出,為了模擬持續(xù)售票的過程,我們需要給它加一個循環(huán) 
  2.      - (void)saleTicket { 
  3.          while (1) { 
  4.              //如果還有票,繼續(xù)售賣 
  5.              if (_ticketCount > 0) { 
  6.                  _ticketCount --; 
  7.                  NSLog(@"%@", [NSString stringWithFormat:@"剩余票數(shù):%ld 窗口:%@", _ticketCount, [NSThread currentThread].name]); 
  8.                  [NSThread sleepForTimeInterval:0.2]; 
  9.              } 
  10.              //如果已賣完,關(guān)閉售票窗口 
  11.              else { 
  12.                  break; 
  13.              } 
  14.          } 
  15.      } 
  1. 執(zhí)行結(jié)果: 
  2.     2016-04-06 19:25:36.637 MutiThread[4705:1371666] 剩余票數(shù):9 窗口:廣州售票窗口 
  3.     2016-04-06 19:25:36.637 MutiThread[4705:1371665] 剩余票數(shù):8 窗口:北京售票窗口 
  4.     2016-04-06 19:25:36.839 MutiThread[4705:1371666] 剩余票數(shù):7 窗口:廣州售票窗口 
  5.     2016-04-06 19:25:36.839 MutiThread[4705:1371665] 剩余票數(shù):7 窗口:北京售票窗口 
  6.     2016-04-06 19:25:37.045 MutiThread[4705:1371666] 剩余票數(shù):5 窗口:廣州售票窗口 
  7.     2016-04-06 19:25:37.045 MutiThread[4705:1371665] 剩余票數(shù):6 窗口:北京售票窗口 
  8.     2016-04-06 19:25:37.250 MutiThread[4705:1371665] 剩余票數(shù):4 窗口:北京售票窗口 
  9.     2016-04-06 19:25:37.250 MutiThread[4705:1371666] 剩余票數(shù):4 窗口:廣州售票窗口 
  10.     2016-04-06 19:25:37.456 MutiThread[4705:1371666] 剩余票數(shù):2 窗口:廣州售票窗口 
  11.     2016-04-06 19:25:37.456 MutiThread[4705:1371665] 剩余票數(shù):3 窗口:北京售票窗口 
  12.     2016-04-06 19:25:37.661 MutiThread[4705:1371665] 剩余票數(shù):1 窗口:北京售票窗口 
  13.     2016-04-06 19:25:37.661 MutiThread[4705:1371666] 剩余票數(shù):1 窗口:廣州售票窗口 
  14.     2016-04-06 19:25:37.866 MutiThread[4705:1371665] 剩余票數(shù):0 窗口:北京售票窗口 
  15.     2016-04-06 19:25:37.867 MutiThread[4705:1371666] <NSThread: 0x7fdc91e289f0>{number = 3name = 廣州售票窗口} Will Exit 
  16.     2016-04-06 19:25:38.070 MutiThread[4705:1371665] <NSThread: 0x7fdc91e24d60>{number = 2name = 北京售票窗口} Will Exit 

可以看到,票的銷售過程中出現(xiàn)了剩余數(shù)量錯亂的情況,這就是前面提到的線程同步問題。

售票是一個典型的需要線程同步的場景,由于售票渠道有很多,而票的資源是有限的,當多個渠道在短時間內(nèi)賣出大量的票的時候,如果沒有同步機制來管理票的數(shù)量,將會導(dǎo)致票的總數(shù)和售出票數(shù)對應(yīng)不上的錯誤。

  1. 我們在售票的過程中給票加上同步鎖:同一時間內(nèi),只有一個線程能對票的數(shù)量進行操作,當操作完成之后,其他線程才能繼續(xù)對票的數(shù)量進行操作。 
  2.      - (void)saleTicket { 
  3.          while (1) { 
  4.              @synchronized(self) { 
  5.                  //如果還有票,繼續(xù)售賣 
  6.                  if (_ticketCount > 0) { 
  7.                      _ticketCount --; 
  8.                      NSLog(@"%@", [NSString stringWithFormat:@"剩余票數(shù):%ld 窗口:%@", _ticketCount, [NSThread currentThread].name]); 
  9.                      [NSThread sleepForTimeInterval:0.2]; 
  10.                  } 
  11.                  //如果已賣完,關(guān)閉售票窗口 
  12.                  else { 
  13.                      break; 
  14.                  } 
  15.              } 
  16.          } 
  17.      } 
  1. 運行結(jié)果: 
  2.     2016-04-06 19:31:27.913 MutiThread[4718:1406865] 剩余票數(shù):11 窗口:北京售票窗口 
  3.     2016-04-06 19:31:28.115 MutiThread[4718:1406866] 剩余票數(shù):10 窗口:廣州售票窗口 
  4.     2016-04-06 19:31:28.317 MutiThread[4718:1406865] 剩余票數(shù):9 窗口:北京售票窗口 
  5.     2016-04-06 19:31:28.522 MutiThread[4718:1406866] 剩余票數(shù):8 窗口:廣州售票窗口 
  6.     2016-04-06 19:31:28.728 MutiThread[4718:1406865] 剩余票數(shù):7 窗口:北京售票窗口 
  7.     2016-04-06 19:31:28.929 MutiThread[4718:1406866] 剩余票數(shù):6 窗口:廣州售票窗口 
  8.     2016-04-06 19:31:29.134 MutiThread[4718:1406865] 剩余票數(shù):5 窗口:北京售票窗口 
  9.     2016-04-06 19:31:29.339 MutiThread[4718:1406866] 剩余票數(shù):4 窗口:廣州售票窗口 
  10.     2016-04-06 19:31:29.545 MutiThread[4718:1406865] 剩余票數(shù):3 窗口:北京售票窗口 
  11.     2016-04-06 19:31:29.751 MutiThread[4718:1406866] 剩余票數(shù):2 窗口:廣州售票窗口 
  12.     2016-04-06 19:31:29.952 MutiThread[4718:1406865] 剩余票數(shù):1 窗口:北京售票窗口 
  13.     2016-04-06 19:31:30.158 MutiThread[4718:1406866] 剩余票數(shù):0 窗口:廣州售票窗口 
  14.     2016-04-06 19:31:30.363 MutiThread[4718:1406866] <NSThread: 0x7ff0c1637320>{number = 3name = 廣州售票窗口} Will Exit 
  15.     2016-04-06 19:31:30.363 MutiThread[4718:1406865] <NSThread: 0x7ff0c1420cb0>{number = 2name = 北京售票窗口} Will Exit 

可以看到,票的數(shù)量沒有出現(xiàn)錯亂的情況。

  線程的持續(xù)運行和退出

我們注意到,線程啟動后,執(zhí)行saleTicket完畢后就馬上退出了,怎樣能讓線程一直運行呢(窗口一直開放,可以隨時指派其賣演唱會的門票的任務(wù)),答案就是給線程加上runLoop

  1. ``` 
  2.      先監(jiān)聽線程退出的通知,以便知道線程什么時候退出 
  3.      [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(threadExitNotice) name:NSThreadWillExitNotification object:nil]; 
  4.  ``` 
  1. //設(shè)置演唱會的門票數(shù)量 
  2.      _ticketCount = 50
  1. 新建兩個子線程(代表兩個窗口同時銷售門票) 
  2.      NSThread * window1 = [[NSThread alloc]initWithTarget:self selector:@selector(thread1) object:nil]; 
  3.      [window1 start]; 
  4.  
  5.      NSThread * window2 = [[NSThread alloc]initWithTarget:self selector:@selector(thread2) object:nil]; 
  6.      [window2 start]; 
  1. 接著我們給線程創(chuàng)建一個runLoop 
  2.      - (void)thread1 { 
  3.          [NSThread currentThread].name = @"北京售票窗口"; 
  4.          NSRunLoop * runLoop1 = [NSRunLoop currentRunLoop]; 
  5.          [runLoop1 runUntilDate:[NSDate date]]; //一直運行 
  6.      } 
  7.  
  8.      - (void)thread2 { 
  9.          [NSThread currentThread].name = @"廣州售票窗口"; 
  10.          NSRunLoop * runLoop2 = [NSRunLoop currentRunLoop]; 
  11.          [runLoop2 runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10.0]]; //自定義運行時間 
  12.      } 
  1. 然后就可以指派任務(wù)給線程了,這里我們讓兩個線程都執(zhí)行相同的任務(wù)(售票) 
  2.      [self performSelector:@selector(saleTicket) onThread:window1 withObject:nil waitUntilDone:NO]; 
  3.      [self performSelector:@selector(saleTicket) onThread:window2 withObject:nil waitUntilDone:NO]; 
  1. 運行結(jié)果: 
  2.      2016-04-06 19:43:22.585 MutiThread[4762:1478200] 剩余票數(shù):11 窗口:北京售票窗口 
  3.      2016-04-06 19:43:22.788 MutiThread[4762:1478201] 剩余票數(shù):10 窗口:廣州售票窗口 
  4.      2016-04-06 19:43:22.993 MutiThread[4762:1478200] 剩余票數(shù):9 窗口:北京售票窗口 
  5.      2016-04-06 19:43:23.198 MutiThread[4762:1478201] 剩余票數(shù):8 窗口:廣州售票窗口 
  6.      2016-04-06 19:43:23.404 MutiThread[4762:1478200] 剩余票數(shù):7 窗口:北京售票窗口 
  7.      2016-04-06 19:43:23.609 MutiThread[4762:1478201] 剩余票數(shù):6 窗口:廣州售票窗口 
  8.      2016-04-06 19:43:23.810 MutiThread[4762:1478200] 剩余票數(shù):5 窗口:北京售票窗口 
  9.      2016-04-06 19:43:24.011 MutiThread[4762:1478201] 剩余票數(shù):4 窗口:廣州售票窗口 
  10.      2016-04-06 19:43:24.216 MutiThread[4762:1478200] 剩余票數(shù):3 窗口:北京售票窗口 
  11.      2016-04-06 19:43:24.422 MutiThread[4762:1478201] 剩余票數(shù):2 窗口:廣州售票窗口 
  12.      2016-04-06 19:43:24.628 MutiThread[4762:1478200] 剩余票數(shù):1 窗口:北京售票窗口 
  13.      2016-04-06 19:43:24.833 MutiThread[4762:1478201] 剩余票數(shù):0 窗口:廣州售票窗口 
  14.      2016-04-06 19:43:25.039 MutiThread[4762:1478201] <NSThread: 0x7fe0d3c24360>{number = 3name = 廣州售票窗口} Will Exit 

可以看到,當票賣完后,兩個線程并沒有退出,仍在繼續(xù)運行,當?shù)竭_指定時間后,線程2退出了,如果需要讓線程1退出,需要我們手動管理。

比如我們讓線程完成任務(wù)(售票)后自行退出,可以這樣操作

  1. - (void)saleTicket { 
  2.         while (1) { 
  3.             @synchronized(self) { 
  4.             //如果還有票,繼續(xù)售賣 
  5.                 if (_ticketCount > 0) { 
  6.                     _ticketCount --; 
  7.                     NSLog(@"%@", [NSString stringWithFormat:@"剩余票數(shù):%ld 窗口:%@", _ticketCount, [NSThread currentThread].name]); 
  8.                     [NSThread sleepForTimeInterval:0.2]; 
  9.                 } 
  10.                 //如果已賣完,關(guān)閉售票窗口 
  11.                 else { 
  12.                     if ([NSThread currentThread].isCancelled) { 
  13.                        break; 
  14.                     }else { 
  15.                        NSLog(@"售賣完畢"); 
  16.                        //給當前線程標記為取消狀態(tài) 
  17.                        [[NSThread currentThread] cancel]; 
  18.                        //停止當前線程的runLoop 
  19.                        CFRunLoopStop(CFRunLoopGetCurrent()); 
  20.                     } 
  21.                 } 
  22.             } 
  23.         } 
  24.     } 
  1. 運行結(jié)果: 
  2.      2016-04-06 20:08:38.287 MutiThread[4927:1577193] 剩余票數(shù):10 窗口:北京售票窗口 
  3.      2016-04-06 20:08:38.489 MutiThread[4927:1577194] 剩余票數(shù):9 窗口:廣州售票窗口 
  4.      2016-04-06 20:08:38.690 MutiThread[4927:1577193] 剩余票數(shù):8 窗口:北京售票窗口 
  5.      2016-04-06 20:08:38.892 MutiThread[4927:1577194] 剩余票數(shù):7 窗口:廣州售票窗口 
  6.      2016-04-06 20:08:39.094 MutiThread[4927:1577193] 剩余票數(shù):6 窗口:北京售票窗口 
  7.      2016-04-06 20:08:39.294 MutiThread[4927:1577194] 剩余票數(shù):5 窗口:廣州售票窗口 
  8.      2016-04-06 20:08:39.499 MutiThread[4927:1577193] 剩余票數(shù):4 窗口:北京售票窗口 
  9.      2016-04-06 20:08:39.700 MutiThread[4927:1577194] 剩余票數(shù):3 窗口:廣州售票窗口 
  10.      2016-04-06 20:08:39.905 MutiThread[4927:1577193] 剩余票數(shù):2 窗口:北京售票窗口 
  11.      2016-04-06 20:08:40.106 MutiThread[4927:1577194] 剩余票數(shù):1 窗口:廣州售票窗口 
  12.      2016-04-06 20:08:40.312 MutiThread[4927:1577193] 剩余票數(shù):0 窗口:北京售票窗口 
  13.      2016-04-06 20:08:40.516 MutiThread[4927:1577194] 售賣完畢 
  14.      2016-04-06 20:08:40.516 MutiThread[4927:1577193] 售賣完畢 
  15.      2016-04-06 20:08:40.517 MutiThread[4927:1577193] <NSThread: 0x7fb719d54000>{number = 2name = 北京售票窗口} Will Exit 
  16.      2016-04-06 20:08:40.517 MutiThread[4927:1577194] <NSThread: 0x7fb719d552f0>{number = 3name = 廣州售票窗口} Will Exit 

如果確定兩個線程都是isCancelled狀態(tài),可以調(diào)用[NSThread exit]方法來終止線程。 

責任編輯:倪明 來源: 明仔Su的簡書
相關(guān)推薦

2013-06-07 16:30:08

iOS多線程iOS開發(fā)NSThread

2013-08-21 16:17:09

iPhone多線程

2013-07-16 13:39:11

2013-07-16 10:12:14

iOS多線程多線程概念多線程入門

2015-07-22 09:39:38

IOS多線程同步

2011-08-02 10:26:59

iOS 多線程 線程

2015-07-22 09:51:51

iOS開發(fā)線程

2021-12-14 08:28:08

Java多線程線程

2021-02-25 15:58:46

C++線程編程開發(fā)技術(shù)

2013-07-16 10:57:34

iOS多線程多線程概念多線程入門

2013-07-16 12:13:27

iOS多線程多線程概念GCD

2013-07-15 15:35:06

2021-07-19 07:55:24

多線程模型Redis

2011-08-18 17:07:23

IOS開發(fā)多線程NSInvocatio

2019-09-24 14:19:12

PythonC語言文章

2021-03-28 09:12:58

多線程死鎖技術(shù)熱點

2015-07-29 09:22:25

IOS多線程

2013-03-27 10:32:53

iOS多線程原理runloop介紹GCD

2013-07-16 11:38:46

iOS多線程多線程概念GCD

2018-04-11 10:51:25

多線程進程主線程
點贊
收藏

51CTO技術(shù)棧公眾號