多線程技術(shù)方案
- pthread
- NSThread
- GCD
- NSOperation
1.pthread
特點
程序員自己管理線程的生命周期
定義
線程庫實行了POSIX線程標準通常稱為Pthreads。
POSIX線程具有很好的可移植性,使用pthreads編寫的代碼可運行于Solaris村缸、FreeBSD自娩、Linux 等平臺透绩,Windows平臺亦有pthreads-win32可供使用 。
Pthreads定義了一套C語言的類型平匈、函數(shù)與常量,它以pthread.h頭文件和一個線程庫實現(xiàn)晋修。
頭文件
#import <pthread.h>
創(chuàng)建線程
/**
- (void)demo {
//1.創(chuàng)建線程對象
pthread_t thread;
/**2.創(chuàng)建線程
參數(shù):
1.指向線程標識符的指針,C 語言中類型的結(jié)尾通常 _t/Ref凰盔,而且不需要使用 *;
2.用來設(shè)置線程屬性;
3.指向函數(shù)的指針,傳入函數(shù)名(函數(shù)的地址)墓卦,線程要執(zhí)行的函數(shù)/任務;
4.運行函數(shù)的參數(shù);
*/
NSString *param = @"參數(shù)";
int result = pthread_create(&thread, NULL, func, (__bridge void *)(param));
if (result == 0) {
NSLog(@"success")
} else {
NSLog(@"failure");
return;
}
//3.設(shè)置子線程的狀態(tài)設(shè)置為detached,則該線程運行結(jié)束后會自動釋放所有資源,或者在子線程中添加 pthread_detach(pthread_self()),其中pthread_self()是獲得線程自身的id
pthread_detach(thread);
}
void *func(void *param) {
//在此做耗時操作
NSLog(@"new thread : %@ 參數(shù)是: %@",[NSThread currentThread],(__bridge NSString *)(param));
return NULL;
}
其他函數(shù)
pthread_t:線程ID
pthread_attr_t:線程屬性
pthread_create():創(chuàng)建一個線程
pthread_exit():終止當前線程
pthread_cancel():中斷另外一個線程的運行
pthread_join():阻塞當前的線程户敬,直到另外一個線程運行結(jié)束
pthread_attr_init():初始化線程的屬性
pthread_attr_setdetachstate():設(shè)置脫離狀態(tài)的屬性(決定這個線程在終止時是否可以被結(jié)合)
pthread_attr_getdetachstate():獲取脫離狀態(tài)的屬性
pthread_attr_destroy():刪除線程的屬性
pthread_kill():向線程發(fā)送一個信號
pthread_equal(): 對兩個線程的線程標識號進行比較
pthread_detach(): 分離線程
pthread_self(): 查詢線程自身線程標識號
2.NSThread
特點
程序員管理線程的生命周期落剪;
使用OC對象, 簡單易用尿庐,可直接操作線程對象
創(chuàng)建方式
1. 實例方法創(chuàng)建線程
- (IBAction)useInstanceMehotd:(id)sender {
NSLog(@"===== begin %@", [NSThread currentThread]);
// 創(chuàng)建NSThread 對象
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(myOperation:) object:@"instance method"];
// 啟動線程 -> 開辟子線程執(zhí)行方法
[thread start];
NSLog(@"===== end %@", [NSThread currentThread]);
}
- (void)myOperation:(id)param {
NSLog(@"begin %@", [NSThread currentThread]);
NSLog(@"param = %@", param);
[NSThread sleepForTimeInterval:3];
NSLog(@"end %@", [NSThread currentThread]);
}
2. 類方法創(chuàng)建線程
- (IBAction)useClassMethod:(id)sender {
NSLog(@"===== begin %@", [NSThread currentThread]);
// 自動創(chuàng)建線程忠怖,并執(zhí)行方法
[NSThread detachNewThreadSelector:@selector(myOperation:) toTarget:self withObject:@"class method"];
NSLog(@"===== end %@", [NSThread currentThread]);
}
- (void)myOperation:(id)param {
NSLog(@"begin %@", [NSThread currentThread]);
NSLog(@"param = %@", param);
[NSThread sleepForTimeInterval:3];
NSLog(@"end %@", [NSThread currentThread]);
}
3. NSObject分類方法創(chuàng)建線程
- (IBAction)useCatgoryMethod:(id)sender {
NSLog(@"===== begin %@", [NSThread currentThread]);
// 是NSObject分類方法
// 自動在后臺線程執(zhí)行
[self performSelectorInBackground:@selector(myOperation:) withObject:@"category method"];
NSLog(@"===== end %@", [NSThread currentThread]);
}
- (void)myOperation:(id)param {
NSLog(@"begin %@", [NSThread currentThread]);
NSLog(@"param = %@", param);
[NSThread sleepForTimeInterval:3];
NSLog(@"end %@", [NSThread currentThread]);
}
3.GCD
特點
不用關(guān)心線程的生命周期
執(zhí)行任務方式
- 同步的方式執(zhí)行:
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
queue: 隊列
block: 任務
- 異步的方式執(zhí)行
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
queue: 隊列
block: 任務
同步:
只能在當前線程中執(zhí)行任務, 不具備開啟線程能力
必須等待任務執(zhí)行完畢抄瑟,才會執(zhí)行下一條語句
異步:
可以在新的線程中執(zhí)行凡泣, 具備開啟新線程能力
不用等待任務執(zhí)行完畢, 就可以執(zhí)行下一條語句
隊列類型
1. 并發(fā)隊列(Concurrent Dispatch Queue)
* 允許多個任務并發(fā)(同時)執(zhí)行
* 并發(fā)功能只有在異步函數(shù)下才有效
2. 串行隊列(Serial Dispatch Queue)
* 讓任務一個接著一個的執(zhí)行
全局隊列(dispatch_get_global_queue): 是一個并發(fā)隊列
主隊列(dispatch_get_main_queue): 主隊列專門用于在主線程上執(zhí)行任務
隊列執(zhí)行效果
并發(fā)隊列 串行隊列
同步 1.沒有開啟新線程 1. 沒有開啟新線程
2.串行執(zhí)行任務 2. 串行執(zhí)行任務
異步 1. 開啟新線程 1. 開啟新線程
2. 并發(fā)執(zhí)行任務 2. 串行執(zhí)行任務
dispatch_barrier|_async 使用
該函數(shù)會等待dispatch_barrier_async 前面所有任務完成
然后在執(zhí)行 dispatch_barrier_async 的任務
- (IBAction)test_barrier_async:(id)sender {
dispatch_queue_t queue = dispatch_queue_create("com.chenxi.learn.thread", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"task1 complete, %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"task2 complete, %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
int time = arc4random() % 5;
[NSThread sleepForTimeInterval:time];
NSLog(@"task3 complete, %@", [NSThread currentThread]);
});
// 阻塞
dispatch_barrier_async(queue, ^{
NSLog(@"barrier asycn task ..., %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"another task1 complete, %@", [NSThread currentThread]);
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"another task2 complete, %@", [NSThread currentThread]);
});
}
GCD 調(diào)度組
使用 dispatch_group_async 和 dispatch_group_notify 函數(shù)來完成調(diào)度組的工作
- (void)demo {
// 1. 調(diào)度組
dispatch_group_t group = dispatch_group_create();
// 2. 并發(fā)隊列
dispatch_queue_t queue = dispatch_queue_create("com.chenxi.learn.thread", DISPATCH_QUEUE_CONCURRENT);
// 3. 任務添加到調(diào)度組
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:3];
NSLog(@"task1 comolete, %@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"task2 comolete, %@", [NSThread currentThread]);
});
dispatch_group_async(group, queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"task3 comolete, %@", [NSThread currentThread]);
});
// 等待所有任務離開調(diào)度組锐借, 調(diào)用該函數(shù)
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"all task completed, %@", [NSThread currentThread]);
});
NSLog(@"other things ...");
}
4. NSOperation
特點
是使用OC語言對GCD的封裝
完全面向?qū)ο笪属铮恍枰芾砭€程的生命周期
NSOperation 只是一個抽象類往衷, 需要使用子類來執(zhí)行任務钞翔。 蘋果提供了兩個子類: NSInvocationOperation 和 NSBlockOperation。
核心
操作(NSoperation): 要做的事情
隊列(NSOperationQueue): 存放操作
使用步驟
創(chuàng)建操作
創(chuàng)建隊列
將操作放入隊列
NSInvocationOperation 使用
- (IBAction)tes_invocation:(id)sender {
NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@{@"name":@"invocationOperation", @"param": @"hello world"}];
// 操作完成回調(diào)
[invocationOperation setCompletionBlock:^{
NSLog(@"end invocation thread = %@", [NSThread currentThread]);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:invocationOperation];
}
- (void)demo:(id)obj {
[NSThread sleepForTimeInterval:arc4random()%4];
NSLog(@"thread = %@, msg = %@", [NSThread currentThread], obj);
}
NSBlockOperation
- (IBAction)test_block:(id)sender {
NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:3];
NSLog(@"block operation 1, thread = %@", [NSThread currentThread]);
}];
// 可以添加多個任務
[blockOperation addExecutionBlock:^{
[NSThread sleepForTimeInterval:1];
NSLog(@"block operation 2, thread = %@", [NSThread currentThread]);
}];
[blockOperation addExecutionBlock:^{
[NSThread sleepForTimeInterval:1.5];
NSLog(@"block operation 3, thread = %@", [NSThread currentThread]);
}];
[blockOperation setCompletionBlock:^{
NSLog(@"end block operation, thread = %@", [NSThread currentThread]);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:blockOperation];
}
操作依賴
- (IBAction)test_dependency:(id)sender {
_queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:3];
NSLog(@"op1 , thread = %@", [NSThread currentThread]);
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:2];
NSLog(@"op2 , thread = %@", [NSThread currentThread]);
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
[NSThread sleepForTimeInterval:0.5];
NSLog(@"op3 , thread = %@", [NSThread currentThread]);
}];
// op1 完成之后席舍,開始op2 / op3 任務
[op2 addDependency:op1];
[op3 addDependency:op1];
[_queue addOperation:op1];
[_queue addOperation:op2];
[_queue addOperation:op3];
NSLog(@"test dependency , thread = %@", [NSThread currentThread]);
}
自定義NSOperation
自定義 Operation 需要繼承 NSOperation 類布轿,并實現(xiàn)其 main() 方法,因為在調(diào)用 start() 方法的時候,內(nèi)部會調(diào)用 main() 方法完成相關(guān)邏輯汰扭。
// 創(chuàng)建 CustomOperation 類稠肘, 繼承自 NSOperation
@interface CustomOperation : NSOperation
@end
@implementation CustomOperation
- (void)main
{
NSTimeInterval time = arc4random() % 6;
[NSThread sleepForTimeInterval:time];
NSLog(@"thread %@", [NSThread currentThread]);
}
@end
// ======= 在其他文件調(diào)用
- (IBAction)test_custom_operation:(id)sender {
CustomOperation *operation1 = [[CustomOperation alloc] init];
CustomOperation *operation2 = [[CustomOperation alloc] init];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation1];
[queue addOperation:operation2];
}
隊列其他方法
maxConcurrentOperationCount 這是最大并發(fā)數(shù)
suspended 隊列暫停/繼續(xù)
cancelAllOperations 取消所有操作