iOS 知識整理--多線程

目錄

多線程--NSThread基本使用

多線程--GCD

任務

隊列

dispatch_sync 同步執行

dispatch_queue_t 創建方法

dispatch_barrier_async 柵欄函數

dispatch_apply 快速迭代

dispatch_after 延時執行方法

dispatch_group_notify 隊列組

dispatch_semaphore 信號量

dispatch_source_t定時器

多線程--NSOperation

NSOperationQueue 隊列

NSOperation 操作

maxConcurrentOperationCount最大併發數

addDependency依賴

其他

多線程--鎖

多線程--GCD和NSOperation對比


多線程--NSThread基本使用

//1.alloc init 創建線程,需要手動啓動線程
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:"aaa"];
[thread start]

//2.分離子線程
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"ssss"];

//3.開啓後臺線程
[self performSelectorInBackground:@selector(run:) withObject:@"aaa"];

多線程--GCD

GCD ( Grand Central Dispatch ) 是異步執行任務的技術之一。

GCD 中兩個核心概念:『任務』 和 『隊列』

 

任務

任務:就是執行操作的意思,換句話說就是你在線程中執行的那段代碼。在 GCD 中是放在 block 中的。

執行任務有兩種方式:『同步執行』 和 『異步執行』

兩者的主要區別是:是否等待隊列的任務執行結束,以及是否具備開啓新線程的能力。

同步執行(sync):

  • 同步添加任務到指定的隊列中,在添加的任務執行結束之前,會一直等待,直到隊列裏面的任務完成之後再繼續執行。
  • 只能在當前線程中執行任務,不具備開啓新線程的能力。

異步執行(async):

  • 異步添加任務到指定的隊列中,它不會做任何等待,可以繼續執行任務。
  • 可以在新的線程中執行任務,具備開啓新線程的能力。

 

隊列

隊列(Dispatch Queue):這裏的隊列指執行任務的等待隊列,即用來存放任務的隊列。

隊列是一種特殊的線性表,採用 FIFO(先進先出)的原則,即新任務總是被插入到隊列的末尾,而讀取任務的時候總是從隊列的頭部開始讀取。每讀取一個任務,則從隊列中釋放一個任務。

在 GCD 中有兩種隊列:『串行隊列』 和 『併發隊列』執行順序不同,以及開啓線程數不同。

串行隊列(Serial Dispatch Queue)等待處理結束:

  • 每次只有一個任務被執行。讓任務一個接着一個地執行。(只開啓一個線程,一個任務執行完畢後,再執行下一個任務)

併發隊列(Concurrent Dispatch Queue)不等待處理結束:

  •  可以讓多個任務併發(同時)執行。(可以開啓多個線程,並且同時執行任務)

 

dispatch_sync 同步執行

  • dispatch_sync() 是線程同步操作,其作用就是阻塞線程,先讓它的block執行完畢,纔會返回。
  • dipatch_sync() 造成死鎖的條件是:如果在同一個串行隊列(不管是不是主隊列)添加同步任務,就會死鎖,反之則不會

 

dispatch_queue_t 創建方法

作用:通過GCD的API生成Dispatch Queue,第一個參數是指定 Dispatch Queue 的名稱,第二個參數是指 dispatch_queue 的類型。

//1、dispatch_queue_create 
dispatch_queue_t queue = dispatch_queue_create("com.example",DISPATCH_QUEUE_SERIAL);//生成Serial Dispatch Queue
dispatch_queue_t queue = dispatch_queue_create("com.example2",DISPATCH_QUEUE_CONCURRENT);//生成Concurrent Dispatch Queue
//2、獲取系統標準提供的 Dispatch Queue

dispatch_get_main_queue();//主線程 Serial Dispatch Queue
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0);//(高優先級)//全局的Concurrent Dispatch Queue,第一參數是優先級,第二個參數暫時沒用
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);//(默認優先級)
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0);//(低優先級)
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0);//(後臺優先級)

 

dispatch_barrier_async 柵欄函數

作用:只有當柵欄函數執行完畢後才能執行後面的函數 
★★★不能使用全局併發隊列
dispatch_barrier_async(queue,^{block});

 

dispatch_apply 快速迭代

作用:按照指定的次數將指定的任務追加到指定的隊列中,並等待全部隊列執行結束

★★★只能使用併發隊列

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"apply---begin");
dispatch_apply(6, queue, ^(size_t index) {
	NSLog(@"%zd---%@",index, [NSThread currentThread]);
});
NSLog(@"apply---end");

 

dispatch_after 延時執行方法

作用:延時操作,在指定時間追加處理到Dispatch Queue

dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW,3*NSEC_PER_SEC);//第一個參數指定時間,第二個參數指定多少秒後的時間
dispatch_after(time,dispatch_get_main_queue(),^{
    NSLog(@"aaa");
});

 

dispatch_group_notify 隊列組

作用:控制任務執行順序

//兩種寫法
//寫法1:
	dispatch_group_async(group,queue);
	dispatch_group_notify(group, queue, ^{
        NSLog(@"end");
    });
//寫法2:
	dispatch_group_enter(group)//在改方法後面的異步任務會被那人到隊列組的監聽範圍,進入羣組
    dispatch_async(queue,^{
        //離開羣組
        dispatch_group_leave(group);
    })

dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
	1、DISPATCH_TIME_FOREVER 死等直到隊列組中所有的任務都執行完畢之後才能執行,阻塞的
	2、DISPATCH_TIME_NOW 直接運行,超時時間爲0

 

dispatch_semaphore 信號量

是持有計數的信號,計數小於0時等待,不可通過。計數爲0或者大於0時,計數減1且不等待,可通過。

  • 保持線程同步,將異步執行任務轉爲同步執行任務
  • 保證線程安全,爲線程加鎖
dispatch_semaphore_semaphore_create://創建一個Semaphore並初始化信號的總量
//這裏的傳入的參數value必須大於或等於0,否則dispatch_semaphore_create會返回NULL。


dispatch_semaphore_signal://發送一個信號,讓信號總量加1
//當返回值不爲0時,表示其當前有(一個或多個)線程等待其處理的信號量,並且該函數喚醒了一個等待的線程(當線程有優先級時,喚醒優先級最高的線程;否則隨機喚醒)。


dispatch_semaphore_wait://可以使總信號量減1,信號總量小於0時就會一直等待(阻塞所在線程),否則就可以正常執行
//這個函數的作用是這樣的,如果信號量的值大於0,該函數所處線程就繼續執行下面的語句,並且將信號量的值減1;
//如果信號量的值爲0,那麼這個函數就阻塞當前線程等待timeout(注意timeout的類型爲dispatch_time_t,不能直接傳入整形或float型數)
//如果等待的期間信號量的值被dispatch_semaphore_signal函數加1了,
//且該函數(即dispatch_semaphore_wait)所處線程獲得了信號量,那麼就繼續向下執行並將信號量減1。
//如果等待期間沒有獲取到信號量或者信號量的值一直爲0,那麼等到timeout時,其所處線程自動執行其後語句。

 

dispatch_source_t定時器

//創建GCD定時器
//1:source的類型  DISPATCH_SOURCE_TYPE_TIMER 表示定時器
//2:描述信息
//3:更詳細的描述信息
//4:隊列,決定定時器中的任務在哪個線程執行
dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(0, 0));

//設置定時器(起始時間|間隔時間|精準度)
/*
1.定時器對象
2.起始時間 DISPATCH_TIME_NOW從現在開始
3.間隔時間
4.精準度 絕對精準0
*/
dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 2.0 * NSEC_PER_SEC, 1 * NSEC_PER_SEC);
//設置定時器執行任務
dispatch_source_set_event_handler(timer, ^{
});
//啓動執行
dispatch_resume(timer);

 

多線程--NSOperation

NSOperation、NSOperationQueue 是蘋果提供給我們的一套多線程解決方案。

實際上 NSOperation、NSOperationQueue 是基於 GCD 更高一層的封裝,完全面向對象。但是比GCD更簡單易用、代碼可讀性也更高。

優點:

  • 可添加完成的代碼塊,在操作完成後執行
  • 添加操作之間的依賴關係,方便的控制執行順序
  • 設定操作執行的優先級
  • 可以很方便的取消一個操作的執行
  • 使用KVO觀察對操作執行狀態的更改:isExecuteing、isFinished、isCancelled

 

NSOperationQueue 隊列

  • 通過 [[NSOperationQueue alloc]init]創建的操作隊列,其內添加的任務在子線程執行。
  • 通過[NSOperationQueue mainQueue] 獲取的是主操作隊列,其內添加的任務(NSOperation)在主線程執行。
  • 如果將NSOperation添加到NSOperationQueue(操作隊列)中,系統自動異步執行NSOperation中的操作。
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:op1];

 

NSOperation 操作

NSOperation是個抽象類,並不具備封裝操作的能力,必須使用它的子類

  • 先將需要執行的操作封裝到一個NSOperation對象中
  • 然後將NSOperation對象添加到NSOperationQueue中
  • 系統會自動將NSOperationQueue中的NSOperation取出來
  • 將取出的NSOperation封裝的操作放到一條新線程中執行

1、NSInvocationOperation

//如果是在主線程創建,就在主線程執行任務。如果是子線程,那就在子線程
//默認情況下,調用了start方法後並不會開一條新線程去執行操作,而是在當前線程同步執行操作
//只有將NSOperation放到一個NSOperationQueue中,纔會異步執行操作

NSInvocationOperation  *operation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run) object:nil];
[operation start];

2、NSBlockOperation

//包裝的任務在主線程
NSBlockOperation  *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"1  --- %@",[NSThread currentThread]);
}];
//再添加的任務 會在新子線程執行
[operation addExecutionBlock:^{
        NSLog(@"2 --- %@",[NSThread currentThread]);  
}];
[operation start];
//只要NSBlockOperation封裝的操作數 > 1,就會異步執行操作

 

maxConcurrentOperationCount最大併發數

作用:控制同一時間執行任務的數量

系統默認最大併發數是NSOperationQueueDefaultMaxConcurrentOperationCount = -1.

  • maxConcurrentOperationCount = 0 不執行隊列
  • maxConcurrentOperationCount = 1 串行隊列 ,串行執行任務不等於只開一條線程
  • maxConcurrentOperationCount > 1 併發隊列

 

addDependency依賴

作用:NSOperation之間可以設置依賴來保證執行順序

注意:可以跨隊列依賴

           不能循環依賴,不會奔潰,不會卡死,只是操作不執行

//比如一定要讓操作A執行完後,才能執行操作B,可以這麼寫
[operationB addDependency:operationA]; // 操作B依賴於操作A

 

其他

暫停 恢復 取消 completion 操作監聽

[queue setSuspended:YES];//可以恢復

//不能暫停當前正在處於執行的任務

[queue setSuspended:NO];

//不可以恢復

//不能取消當前正在執行的任務

[queue cancelAllOperation]

作用:監聽操作有沒有執行完

注意:和監聽的操作使用不同的線程

op.completionBlock=^{}

 

多線程--鎖

  • NSLock 一種低級別的鎖,一旦獲取了鎖,執行則進入臨界區,且不會允許超過一個線程並行執行。釋放鎖則標記着臨界區的結束

[self.lock lock];

//線程安全的代碼

[self.lock unlock];

  • NSRecursiveLock 允許在被解鎖前鎖定多次。如果解鎖的次數與鎖定的次數相匹配,則認爲鎖被釋放,其他線程可以獲取鎖。
  • NSCondition 一個線程可能需要等待其他線程返回結果

 

多線程--GCD和NSOperation對比

GCD

NSOperation

GCD是C的函數封裝

NSOperation是Objective-C類,可以子類化。底層由GCD實現。

支持取消整個Queue的任務,支持block任務取消dispatch_block_cance

支持取消單個NSOperation或整個Queue的任務

支持暫停和恢復dispatch_suspend 和 dispatch_resume

支持隊列暫停和恢復queue.suspended

通過group來實現

支持任務之間的依賴關係

隊列具有優先級

任務具有優先級

GCD 是嚴格的隊列,先進先出 FIFO

NSOperation可以改動 優先級(或者說服務質量)改變執行順序

GCD信號量dispatch_semaphore

可以設置最大併發數

 

可以採用KVO監聽任務狀態

GCD性能更佳,使用簡單

NSOperationQueue更靈活,框架封裝往往採用NSOperationQueue

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章