iOS基礎(chǔ)--多線程簡單總結(jié)(NSThread、NSOperation、NSOperationQueue))

原來一切都來不及
多線程.png

多線程概念


  • 程序: 由源代碼生成的可執(zhí)行應(yīng)用.
  • 進(jìn)程: 一個正在運(yùn)行的程序可以看做一個進(jìn)程. (例如: 正在運(yùn)行的QQ就是一個進(jìn)程) , 進(jìn)程擁有獨(dú)立運(yùn)行所需的全部資源.
  • 線程: 程序中獨(dú)立運(yùn)行的代碼段.

注:一個進(jìn)程是由一或多個線程組成. 進(jìn)程只負(fù)責(zé)資源的調(diào)度和分配,線程才是程序真正的執(zhí)行單元,負(fù)責(zé)代碼的執(zhí)行.

  • 單線程:

1、每個正在運(yùn)行的程序(即 進(jìn)程),至少包含一個線程, 這個線程叫 主線程
2、主線程在程序啟動時被創(chuàng)建,用于執(zhí)行mian函數(shù)
3、只有一個主線程的程序,稱作單線程程序
3、在單線程程序中,主線程負(fù)責(zé)執(zhí)行程序的所有代碼(UI 展現(xiàn)以及刷新,網(wǎng)絡(luò)請求, 本地存儲等). 這些代碼只能順序執(zhí)行, 無法并發(fā)執(zhí)行 .

  • 多線程:

1、擁有多個線程的程序,稱作多線程程序
2、iOS 允許用戶自己開辟新的線程, 相對于主線程來講, 這些線程, 稱作子線程
3、可以根據(jù)需要開辟若干子線程
4、子線程和主線程 都是 獨(dú)立 的運(yùn)行單元, 各自的執(zhí)行互不影響, 因此能夠并發(fā)執(zhí)行

  • 單線程,多線程區(qū)別 :

1、單線程程序: 只有一個線程, 即主線程, 代碼順序執(zhí)行,容易出現(xiàn)代碼阻塞(頁面假死)
2、多線程程序: 有多個線程, 線程間獨(dú)立運(yùn)行, 能有效的避免代碼阻塞,并且提高程序的運(yùn)行性能.

注意: iOS關(guān)于UI的添加和刷新必須在主線程中操作.//開發(fā)中依賴于多線程: 網(wǎng)絡(luò) :(主線程:(UI),子線程(取數(shù)據(jù)))

  • iOS多線程實(shí)現(xiàn)種類

NSObject
NSThread
NSOperationQueue
GCD


NSObject 和 NSThread


#pragma mark ---------NSObject 開辟子線程
// NSObject 開辟子線程
// 參數(shù) 1: selector, 子線程執(zhí)行的代碼(方法名)
// 參數(shù) 2: 表示selector傳遞的參數(shù)
[self performSelectorInBackground:@selector(sayHi) withObject:@"hahah"];

#pragma mark ---------NSThread 手動開辟子線程
// NSThread 開辟一個子線程
// 參數(shù) 1: target
// 參數(shù) 2: action
// 參數(shù) 3: 傳參
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(sayHi) object:nil];
//開啟子線程 [thread start];
//取消 (給線程發(fā)送結(jié)束消息,不會真正的取消掉線程,而是標(biāo)記 這個被取消了)
[thread cancel];
//立即結(jié)束線程
[NSThread exit];
//對于NSObject 和 NSThread實(shí)現(xiàn)的多線程,在任務(wù)完成之后,線程會被自動釋放
//判斷一個線程是否正在執(zhí)行
[thread isExecuting];
//判斷一個線程是否完成了任務(wù)(是否執(zhí)行完畢)
[thread isFinished];
#pragma mark -----------NSThread 自動開辟一個線程
//使用NSThread自動開辟一個線程
//不需要手動開啟線程
[NSThread detachNewThreadSelector:@selector(sayHi) toTarget:self withObject:nil];

//幾秒后執(zhí)行某件事情
[self performSelector:@selector(time) withObject:self afterDelay:3.0f];
}
//讓線程休眠2秒
[NSThread sleepForTimeInterval:2];

- (void)sayHi{
// [NSThread currentThread]; 獲取當(dāng)前的線程
NSLog(@" %@ ", [NSThread currentThread]);
// [NSThread mainThread]; 獲取主線程
NSLog(@" %@ ", [NSThread mainThread]);
// [NSThread isMainThread] 判斷當(dāng)前線程是不是主線程
NSLog(@" %d ", [NSThread isMainThread]);

#pragma mark ----------NSObject
//NSObject中回到主線程去做某事
// 參數(shù) 1: 回到主線程做的事情
// 參數(shù) 2: 傳遞的參數(shù)
// 參數(shù) 3: NO:當(dāng)前的線程任務(wù)已經(jīng)結(jié)束才去做 YES: 執(zhí)行完 selector任務(wù)后才執(zhí)行當(dāng)前線程的其他任務(wù)
[self performSelectorOnMainThread:@selector(onMainThread) withObject:nil waitUntilDone:YES];
\ #pragma mark -----------NSThread 手動
for (int i = 0; i < 10000; i++) { NSLog(@" %d ", i);
if (i == 5000) {
//關(guān)閉線程
// 寫在哪里 哪個線程就關(guān)閉了, 注意 不要隨意的使用. 使用的時候一定要注意當(dāng)前的線程 是否主線程
[NSThread exit]; }
}
}

- (void)onMainThread{
    self.view.backgroundColor = [UIColor orangeColor];   
    NSLog(@"mian --> %@ ", [NSThread mainThread]);   
    NSLog(@"current --> %@", [NSThread currentThread]);
}```


-----
NSOperation和NSOperationQueue
------
------
- NSOperation :

>1、NSOperation類, 在MVC中屬于M, 是用來封裝單個任務(wù)相關(guān)的代碼和數(shù)據(jù)的抽象類
2、因?yàn)樗橄蟮?不能夠直接使用這個類,而是使用子類(NSInvocationOperation或NSBlockOperation) 來執(zhí)行實(shí)際任務(wù).
3、NSOperation(含子類),  只是一個操作, 本身無主線, 子線程之分, 可在任意線程中使用. 通常與NSOperationQueue結(jié)合使用.

- NSOperationQueue
>1、NSOperationQueue是操作隊(duì)列,它用來管理一組Operation對象的執(zhí)行,會根據(jù)需要自動為Operation開辟合適數(shù)量的線程,以完成任務(wù)并行執(zhí)行
2、其中NSOperation可以調(diào)節(jié)它在隊(duì)列中的優(yōu)先級 (使用addDependency: 設(shè)置依賴關(guān)系)
3、當(dāng)最大并發(fā)數(shù)設(shè)置為1的時候,能實(shí)現(xiàn)線程同步 (串行執(zhí)行);
-------

//NSOperation 是一個抽象類,不能直接使用
//NSOperation類及其子類本身不會進(jìn)行線程的創(chuàng)建
\#pragma mark —————NSInvocationOperation
   //通過NSInvocationOperation類來創(chuàng)建一個NSOperation對象    
```code
NSInvocationOperation *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(hehehe) object:nil];`
    //operation 在單獨(dú)使用的時候 一定要調(diào)用開始方法
   ` [operation start];```
\#pragma mark —————NSBlockOperation
     
```code
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{  
  NSLog(@"block main --> %@", [NSThread mainThread]);
  NSLog(@"block current --> %@", [NSThread currentThread]);    }];
//operation 在單獨(dú)使用的時候 一定要調(diào)用開始方法
    [blockOperation start];```
 \#pragma mark —————NSOperationQueue
  `  NSOperationQueue *queue = [[NSOperationQueue alloc]init];`
     //隊(duì)列添加operation子類,并調(diào)用方法
   ` [queue addOperation:operation];
    [queue addOperation:blockOperation]; `
  //依賴關(guān)系  (只有 參數(shù)線程 執(zhí)行完,才能執(zhí)行,之前是隨機(jī)交錯進(jìn)行的)
  `  [operation addDependency:blockOperation];`
      //獲取 系統(tǒng)提供的隊(duì)列   
```code
 NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];}
- (void)hehehe{       
NSLog(@"hehehe main --> %@", [NSThread mainThread]); 
NSLog(@"hehehe current --> %@", [NSThread currentThread]);    
NSLog(@" %d ", [NSThread isMainThread]);
}```
```code
- (void)touchesBegan:(NSSet<UITouch *> \*)touches withEvent:(UIEvent \*)event{       
//NSOperationQueue 是一個隊(duì)列管理器,可以根據(jù)operation任務(wù)自己,分配線程,自己管理線程的生命周期  
//在開發(fā)過程中,我們不需要管理線程的創(chuàng)建和銷毀 
//NSOperationQueue 創(chuàng)建的是n個并行的線程 
 NSOperationQueue *queue = [[NSOperationQueue alloc]init];
//最大線程并發(fā)數(shù) 
//設(shè)置這個參數(shù)之后,NSOperationQueue表示同時執(zhí)行任務(wù)的最大數(shù)量 
//即使只執(zhí)行一個任務(wù),系統(tǒng)有時候也會開辟多個線程去執(zhí)行這個任務(wù) 
 queue.maxConcurrentOperationCount = 1; 
for (int i = 0; i < 10; i++) ``
{  
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{   
         NSLog(@"current --> %@ main --> %@",[NSThread currentThread],[NSThread mainThread]);     }]; 
[queue addOperation:blockOperation];    }}```

------
GCD
-------
--------
##Grand Central Dispatch (GCD)是Apple開發(fā)的一種多核編程技術(shù).主要用于優(yōu)化應(yīng)用程序以支持多核處理器以及其他對稱處理系統(tǒng).

###GCD提供函數(shù)實(shí)現(xiàn)多線程開發(fā),性能更好,功能也更加強(qiáng)大.

- ###核心概念:
1、任務(wù): 具有一個訂功能的代碼段.一般是一個block或者函數(shù)
2、分發(fā)隊(duì)列: GCD以隊(duì)列的方式進(jìn)行工作,FIFO(先入先出隊(duì)列)
3、GCD會根據(jù)分發(fā)隊(duì)列的類型, 創(chuàng)建合適數(shù)量的線程執(zhí)行隊(duì)列中的任務(wù)

- ###GCD中的兩種隊(duì)列 dispatch_queue:
- SerialQueue(串行) : 一次只執(zhí)行一個任務(wù). Serial queue通常用于同步訪問,特定的資源或數(shù)據(jù).當(dāng)你創(chuàng)建多個Serial queue時,雖然他們各自是同步執(zhí)行的,但Serial queue于Serial queue之間是并發(fā)執(zhí)行的.SerialQueue能實(shí)現(xiàn)線程同步.
- Concurrent(并發(fā)) : 可以并發(fā)地執(zhí)行多個任務(wù),但是遵守FIFO(先入先出隊(duì)列 )

--------

--------

\#pragma mark ----------GCD串行隊(duì)列
//     1) 系統(tǒng)提供的一個串行隊(duì)列
//    使用系統(tǒng)提供的串行隊(duì)列 (主隊(duì)列,也就是在主線程里一次執(zhí)行任務(wù))
   ` dispatch_queue_t queue = dispatch_get_main_queue();`
 //     2) 創(chuàng)建一個串行隊(duì)列
//     參數(shù) 1: 自己創(chuàng)建隊(duì)列的名(蘋果推薦使用反向域名去命名注意沒有@)
//     參數(shù) 2: 系統(tǒng)提供好的一個宏(DISPATCH_QUEUE_SERIAL=NULL)
//     這種方式創(chuàng)建的隊(duì)列,會開辟子線程去執(zhí)行任務(wù)
 `   dispatch_queue_t queue = dispatch_queue_create("name", DISPATCH_QUEUE_SERIAL);`
------

------


\#pragma mark ----------GCD并行隊(duì)列    //     1) 使用系統(tǒng)提供的并行隊(duì)列
//    參數(shù) 1: 表示隊(duì)列的優(yōu)先級 (
         DISPATCH_QUEUE_PRIORITY_BACKGROUND,
         DISPATCH_QUEUE_PRIORITY_LOW,
         DISPATCH_QUEUE_PRIORITY_HEIGH,
         DISPATCH_QUEUE_PRIORITY_DEFAULT)
// 參數(shù) 2: 系統(tǒng)保留字段
`dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);`
//     2) 創(chuàng)建并行隊(duì)列
   ` dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);`

--------

--------


\#pragma mark ----------GCD 功能
    //使用dispatch_async() 向隊(duì)列添加任務(wù),任務(wù)會排隊(duì)執(zhí)行
 // 任務(wù)雖會順序排隊(duì)執(zhí)行,但如果用并發(fā)隊(duì)列(CONCURRENT),可能輸出順序不一樣.
       
```code
dispatch_async(queue, ^{ 
NSLog(@"1 mian --> %@, current --> %@",[NSThread mainThread],[NSThread currentThread]);    });
dispatch_async(queue, ^{ 
NSLog(@"2 mian --> %@, current --> %@",[NSThread mainThread],[NSThread currentThread]);    }); 
dispatch_async(queue, ^{ 
NSLog(@"3 mian --> %@, current --> %@",[NSThread mainThread],[NSThread currentThread]);
    });    ```

 // dispatch_after()
//往隊(duì)列中添加任務(wù),任務(wù)不但會排隊(duì),還會在延遲的時間點(diǎn)執(zhí)行    
```code
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
NSLog(@"已經(jīng)3秒之后了");
    });```

 //dispatch_apply();
//往隊(duì)列中添加任務(wù),任務(wù)會重復(fù)執(zhí)行n次
// 參數(shù) 1: 一共執(zhí)行次數(shù)
// 參數(shù) 2: 執(zhí)行的隊(duì)列 
// 參數(shù) 3: 當(dāng)前索引 

```code
dispatch_apply(3, queue, ^(size_t index) {        
NSLog(@" %zu ", index);
    });```

//分組   
//創(chuàng)建一個分組  
`dispatch_group_t group = dispatch_group_create(); `
//創(chuàng)建一個隊(duì)列
`dispatch_queue_t queue = dispatch_queue_create("000", DISPATCH_QUEUE_CONCURRENT); `      
//向分組中添加一個任務(wù)
` dispatch_group_async(group, queue, ^{ 
NSLog(@"1");    }); `
//向分組添加 最后執(zhí)行的任務(wù)(不能添加為第一個) 
`dispatch_group_notify(group, queue, ^{  
NSLog(@"last one");
    })`
 //將任務(wù)添加到隊(duì)列,此任務(wù)執(zhí)行的時候,其他任務(wù)停止執(zhí)行,所以它輸出順序不改變
    
```code
dispatch_barrier_async(queue, ^{ 
NSLog(@"不變位置的2");    }); 
dispatch_group_async(group, queue, ^{  
 NSLog(@"3");
    });
}```

####**dispatch_once() //將任務(wù)添加到隊(duì)列, 但任務(wù)在程序運(yùn)行過程中,只執(zhí)行一次**

//創(chuàng)建單例類
\#import "MyObject.h"static MyObject *object = nil;

\+ (MyObject *)sharedMyObject{ 
//表示同意時間內(nèi), 只有一個線程可以訪問block塊里面的內(nèi)容  
//dispatch_once 系統(tǒng)封裝好的代碼塊 
```code
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ 
 if (object == nil) {
object = [MyObject new];    }    });    
return object;}```

>dispatch_sync() //將任務(wù)添加到隊(duì)列, block不執(zhí)行完,下面代碼不會執(zhí)行
dispatch_async() //將任務(wù)添加到隊(duì)列,不等內(nèi)部block執(zhí)行完,就去執(zhí)行下面代碼
dispatch_async_f() //將任務(wù)添加到隊(duì)列, 任務(wù)是函數(shù),非Block

--------
線程間的通信
---------
---------
>線程間通信分為兩種:
- 主線程進(jìn)入子線程 (前面的方法都可以)
- 子線程回到主線程

\#pragma mark ----------NSObject
 \ -(void)viewDidLoad{
//NSObject中回到主線程去做某 
 // 參數(shù) 1: 回到主線程做的事情    
// 參數(shù) 2: 傳遞的參數(shù)    
// 參數(shù) 3: 知道當(dāng)前的線程已經(jīng)結(jié)束才去做
 ```code
   [self performSelectorOnMainThread:@selector(onMainThread) withObject:nil waitUntilDone:YES];
}`
\- (void)onMainThread{
    `self.view.backgroundColor = [UIColor orangeColor];   
    NSLog(@"mian --> %@ ", [NSThread mainThread]);   
    NSLog(@"current --> %@", [NSThread currentThread]);`
}
\#pragma mark —————GCD

\- (void)loadData{ 
`NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionTask *task = [session dataTaskWithURL:[NSURL URLWithString:@"https://www.baidu.com"] completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
 if (error == nil) { 
dispatch_async(dispatch_get_main_queue(), ^{ 
//這里去做更新UI的事情
 });   }    }];
}```

--------
- ###線程互斥

> 1、多線程并行編程中,線程間同步與互斥是一個很有技巧也是很容易出錯的地方.
2、線程間互斥應(yīng)對的是這種場景: 多個線程操作統(tǒng)一資源(即某個對象),需要保證線程在對資源的狀態(tài)(即對象的成員變量)進(jìn)行一些非原子性操作后,狀態(tài)仍然正確.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • NSThread 第一種:通過NSThread的對象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 952評論 0 3
  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似。...
    Dely閱讀 9,401評論 21 42
  • 一、多線程簡介: 所謂多線程是指一個 進(jìn)程 -- process(可以理解為系統(tǒng)中正在運(yùn)行的一個應(yīng)用程序)中可以開...
    尋形覓影閱讀 1,183評論 0 6
  • 沒有去西安之前,西安在我的印象中就像《三槍拍案驚奇》里的大漠北的感覺,總是有一種這地方兒缺水的感覺先入為主,以至于...
    苗子愛吃肉閱讀 523評論 2 1
  • 已是22點(diǎn)了,睡前照例不經(jīng)意查閱下微信,竟發(fā)現(xiàn)我所在寫作組的朋友們都在陸續(xù)地上傳作業(yè),十一月份雖說已沒規(guī)定要交作業(yè)...
    與你畫夕陽閱讀 451評論 0 0

友情鏈接更多精彩內(nèi)容