目錄
maxConcurrentOperationCount最大併發數
多線程--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 |