NSThread
NSThread是輕量級的多線程開發(fā),使用起來也并不復雜滑频,但是使用NSThread需要自己管理線程生命周期腺逛。
NSthread的初始化
- 動態(tài)方法
- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;
// 初始化線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
// 設置線程的優(yōu)先級(0.0 - 1.0著拭,1.0最高級)
thread.threadPriority = 1;
// 開啟線程
[thread start];
參數解析:
selector :線程執(zhí)行的方法纱扭,這個selector最多只能接收一個參數target :selector消息發(fā)送的對象argument : 傳給selector的唯一參數,也可以是nil
- 靜態(tài)方法
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
// 調用完畢后茫死,會馬上創(chuàng)建并開啟新線程
- 隱式創(chuàng)建線程的方法
[self performSelectorInBackground:@selector(run) withObject:nil];
獲取當前線程
NSThread *current = [NSThread currentThread];
獲取主線程
NSThread *main = [NSThread mainThread];
暫停當前線程
// 暫停2s
[NSThread sleepForTimeInterval:2];
// 或者
NSDate *date = [NSDate dateWithTimeInterval:2 since Date:[NSDate date]];
[NSThread sleepUntilDate:date];
線程間的通信
- 在指定線程上執(zhí)行操作
[self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES];
- 在主線程上執(zhí)行操作
[self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];
- 在當前線程執(zhí)行操作
[self performSelector:@selector(run) withObject:nil];
優(yōu)缺點
1.優(yōu)點:NSThread比其他兩種多線程方案較輕量級跪但,更直觀地控制線程對象
2.缺點:需要自己管理線程的生命周期,線程同步峦萎。線程同步對數據的加鎖會有一定的系統(tǒng)開銷
NSOperation
使用NSOperation和NSOperationQueue進行多線程開發(fā)類似于 java 中的線程池,只要將一個NSOperation(實際開中需要使用其子類NSInvocationOperation忆首、NSBlockOperation)放到NSOperationQueue這個隊列中線程就會依次啟動爱榔。NSOperationQueue負責管理、執(zhí)行所有的NSOperation糙及,在這個過程中可以更加容易的管理線程總數和控制線程之間的依賴關系详幽。
NSOperation有兩個常用子類用于創(chuàng)建線程操作:NSInvocationOperation和NSBlockOperation,兩種方式本質沒有區(qū)別浸锨,但是是后者使用Block形式進行代碼組織唇聘,使用相對方便。
NSInvocationOperation *invocationOperation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(loadImage) object:nil];
//創(chuàng)建完NSInvocationOperation對象并不會調用柱搜,它由一個start方法啟動操作迟郎,但是注意如果直接調用start方法,則此操作會在主線程中調用聪蘸,一般不會這么操作,而是添加到NSOperationQueue中
// [invocationOperation start];
//創(chuàng)建操作隊列
NSOperationQueue *operationQueue=[[NSOperationQueue alloc]init];
//注意添加到操作隊后宪肖,隊列會開啟一個線程執(zhí)行此操作
[operationQueue addOperation:invocationOperation];
NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{
[self loadImage];
}];
1.使用NSBlockOperation方法,所有的操作不必單獨定義方法健爬,同時解決了只能傳遞一個參數的問題控乾。
2.調用主線程隊列的addOperationWithBlock:方法進行UI更新,不用再定義一個參數實體(之前必須定義一個KCImageData解決只能傳遞一個參數的問題)娜遵。
3.使用NSOperation進行多線程開發(fā)可以設置最大并發(fā)線程蜕衡,有效的對線程進行了控制(上面的代碼運行起來你會發(fā)現(xiàn)打印當前進程時只有有限的線程被創(chuàng)建,如上面的代碼設置最大線程數為5设拟,則圖片基本上是五個一次加載的)
GCD
// 獲取默認優(yōu)先級的全局并發(fā)dispatch queue
dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
// 串行隊列
dispatch_queue_t queue2 = dispatch_queue_create("test", NULL);
dispatch_async(queue1, ^{
NSLog(@"開啟了一個異步任務慨仿,當前線程:%@", [NSThread currentThread]);
});
dispatch_sync(queue2, ^{
NSLog(@"開啟了一個同步任務鸽扁,當前線程:%@", [NSThread currentThread]);
});
并發(fā)隊列同樣是使用dispatch_queue_create()方法創(chuàng)建,只是最后一個參數指定為DISPATCH_QUEUE_CONCURRENT進行創(chuàng)建镶骗,但是在實際開發(fā)中我們通常不會重新創(chuàng)建一個并發(fā)隊列而是使用dispatch_get_global_queue()方法取得一個全局的并發(fā)隊列
- 其他任務執(zhí)行方法
GCD執(zhí)行任務的方法并非只有簡單的同步調用方法和異步調用方法桶现,還有其他一些常用方法:
dispatch_apply():重復執(zhí)行某個任務,但是注意這個方法沒有辦法異步執(zhí)行(為了不阻塞線程可以使用dispatch_async()包裝一下再執(zhí)行)鼎姊。
dispatch_once():單次執(zhí)行一個任務骡和,此方法中的任務只會執(zhí)行一次,重復調用也沒辦法重復執(zhí)行(單例模式中常用此方法)相寇。
dispatch_time():延遲一定的時間后執(zhí)行慰于。
dispatch_barrier_async():使用此方法創(chuàng)建的任務首先會查看隊列中有沒有別的任務要執(zhí)行,如果有唤衫,則會等待已有任務執(zhí)行完畢再執(zhí)行婆赠;同時在此方法后添加的任務必須等待此方法中任務執(zhí)行后才能執(zhí)行。(利用這個方法可以控制執(zhí)行順序佳励,例如前面先加載最后一張圖片的需求就可以先使用這個方法將最后一張圖片加載的操作添加到隊列休里,然后調用dispatch_async()添加其他圖片加載任務)
dispatch_group_async():實現(xiàn)對任務分組管理,如果一組任務全部完成可以通過dispatch_group_notify()方法獲得完成通知(需要定義dispatch_group_t作為分組標識)赃承。