pthread
一套用C語言的通用的多線程API孝情,可以跨平臺、可移植洒嗤,適用于windows箫荡、Linux、Unix平臺渔隶,由于使用難度較大羔挡,線程生命周期由程序員管理線程,幾乎不怎么使用
// 使用pthread創(chuàng)建線程對象
pthread_t thread;
NSString *name = @"ceshi";
// 使用pthread創(chuàng)建線程
// 第一個參數(shù):線程對象地址
// 第二個參數(shù):線程屬性
// 第三個參數(shù):指向函數(shù)的執(zhí)行
// 第四個參數(shù):傳遞給該函數(shù)的參數(shù)
pthread_create(&thread, NULL, run, (__bridge void *)(name));
NSThread
使用OC更傾向于面向?qū)ο蠹浒Γ啽闶褂媒首啤>€程生命周期由程序員管理線程,偶爾使用呈野。
// 第一個參數(shù):目標(biāo)對象
// 第二個參數(shù):選擇器低矮,線程啟動要調(diào)用哪個方法
// 第三個參數(shù):前面方法要接收的參數(shù)(最多只能接收一個參數(shù),沒有則傳nil)
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
// 啟動線程
[thread start];
+ (NSThread *)mainThread; 獲得主線程
- (BOOL)isMainThread; 是否為主線程
+ (BOOL)isMainThread; 是否為主線程
// 獲得當(dāng)前線程
NSThread *current = [NSThread currentThread];
// 啟動線程
- (void)start;
// 進(jìn)入就緒狀態(tài) ->運(yùn)行狀態(tài)被冒。當(dāng)線程任務(wù)執(zhí)行完畢军掂,自動進(jìn)入死亡狀態(tài)
// 設(shè)置線程的優(yōu)先級,注意線程優(yōu)先級的取值范圍為0.0~1.0之間,1.0表示線程的優(yōu)先級最高,如果不設(shè)置該值昨悼,那么理想狀態(tài)下默認(rèn)為0.5
thread.threadPriority = 1.0;
[NSThread exit]; // 退出當(dāng)前線程
[NSThread sleepForTimeInterval:2.0]; // 阻塞線程
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]]; // 阻塞線程
/********************************************另外兩種創(chuàng)建線程方法*******************************************/
// 第二種創(chuàng)建線程的方式:分離出一條子線程
// 特點(diǎn):自動啟動線程蝗锥,無法對線程進(jìn)行更詳細(xì)的設(shè)置
// 第一個參數(shù):線程啟動調(diào)用的方法
// 第二個參數(shù):目標(biāo)對象
// 第三個參數(shù):傳遞給調(diào)用方法的參數(shù)
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
// 第三種創(chuàng)建線程的方式:后臺線程
// 特點(diǎn):自動啟動縣城,無法進(jìn)行更詳細(xì)設(shè)置
[self performSelectorInBackground:@selector(run) withObject:nil];
/********************************************線程間通訊*******************************************/
// 線程間通信常用方法
// 開啟一條子線程來do something
[NSThread detachNewThreadSelector:@selector(doSomething) toTarget:self withObject:nil];
-(void) doSomething{
// 回到主線程刷新UI
// 第一種方式
[self performSelectorOnMainThread:@selector(showSomething:) withObject:image waitUntilDone:YES];
// 第二種方式
[self.imageView performSelectorOnMainThread:@selector(showSomething:) withObject:image waitUntilDone:YES];
// 第三種方式
[self.imageView performSelector:@selector(showSomething:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
}
GCD (Grand Central Dispatch)
C語言幔戏,GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案,會自動利用更多的CPU內(nèi)核(比如雙核玛追、四核),會自動管理線程的生命周期(創(chuàng)建線程税课、調(diào)度任務(wù)闲延、銷毀線程),程序員只需要告訴GCD想要執(zhí)行什么任務(wù),不需要編寫任何線程管理代碼.
// GCD中有2個用來執(zhí)行任務(wù)的函數(shù)
// 用同步的方式執(zhí)行任務(wù)
// queue:隊(duì)列 block:任務(wù)
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
// 用異步的方式執(zhí)行任務(wù)(主要掌握)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
GCD的隊(duì)列可以分為2大類型 :
- 并發(fā)隊(duì)列(Concurrent Dispatch Queue)(并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效)
- 串行隊(duì)列(Serial Dispatch Queue)
并發(fā)隊(duì)列
// 使用dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// (里面的參數(shù)第一個為優(yōu)先級,可以默認(rèn)為固定寫法)列
// 全局并發(fā)隊(duì)列的優(yōu)先級
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 默認(rèn)(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN 后臺
串行隊(duì)列
// GCD中獲得串行有2種途徑
// 1.使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列
// dispatch_queue_t
// dispatch_queue_create(const char*label, 隊(duì)列名稱
// dispatch_queue_attr_t attr); 隊(duì)列屬性韩玩,一般用NULL即可
// 創(chuàng)建一個串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("cn.queue", NULL);
dispatch_release(queue); // 非ARC需要釋放手動創(chuàng)建的隊(duì)列
// 2.使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列,肯定是串行隊(duì)列)
// 主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列
// 放在主隊(duì)列中的任務(wù)垒玲,都會放到主線程中執(zhí)行
// 使用dispatch_get_main_queue()獲得主隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
延時執(zhí)行
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
// 使用GCD函數(shù)
// DISPATCH_TIME_NOW:現(xiàn)在開始的意思
// 2.0 * NSEC_PER_SEC:設(shè)置的秒數(shù)(直接更改數(shù)字即可)
// dispatch_get_main_queue():主隊(duì)列的意思
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// 2秒后執(zhí)行這里的代碼... 在哪個線程執(zhí)行,跟隊(duì)列類型有關(guān)
});
一次性代碼
// 使用dispatch_once函數(shù)能保證某段代碼在程序運(yùn)行過程中只被執(zhí)行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// 程序運(yùn)行過程中,永遠(yuǎn)只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)
});
隊(duì)列組
// 有這么1種需求首先:分別異步執(zhí)行2個耗時的操作 ; 其次:等2個異步操作都執(zhí)行完畢后找颓,再回到主線程執(zhí)行操作
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執(zhí)行1個耗時的異步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 執(zhí)行1個耗時的異步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 等前面的異步操作都執(zhí)行完畢后合愈,回到主線程...
});
// 它會等組里面所有的任務(wù)(同上的兩個block代碼內(nèi)容)都執(zhí)行完了以后,它會調(diào)用_notify里面的這個block;
GCD基本使用
01 異步函數(shù) + 并發(fā)隊(duì)列:開啟多條線程,并發(fā)執(zhí)行任務(wù)
02 異步函數(shù) + 串行隊(duì)列:開啟一條線程,串行執(zhí)行任務(wù)
03 同步函數(shù) + 并發(fā)隊(duì)列:不開線程佛析,串行執(zhí)行任務(wù)
04 同步函數(shù) + 串行隊(duì)列:不開線程益老,串行執(zhí)行任務(wù)
05 異步函數(shù) + 主隊(duì)列:不開線程,在主線程中串行執(zhí)行任務(wù)
06 同步函數(shù) + 主隊(duì)列:不開線程寸莫,串行執(zhí)行任務(wù)(注意死鎖發(fā)生)
07 注意同步函數(shù)和異步函數(shù)在執(zhí)行順序上面的差異
NSOperation
OC語言捺萌,基于GCD,切比GCD多了一些更便捷的實(shí)用功能膘茎,更加面向?qū)ο蠡?桃纯,線程生命周期自動線程管理且經(jīng)常使用。
配合使用NSOperation和NSOperationQueue也能實(shí)現(xiàn)多線程編程披坏。
首先將需要執(zhí)行的操作封裝到一個NSOperation對象中态坦,然后將NSOperation對象添加到NSOperationQueue中,系統(tǒng)會自動將NSOperationQueue中的NSOperation取出來棒拂,將取出的NSOperation封裝的操作放到一條新線程中執(zhí)行伞梯。
NSOperation的子類:
NSInvocationOperation
NSBlockOperation
自定義子類繼承NSOperation,實(shí)現(xiàn)內(nèi)部相應(yīng)的方法
NSInvocationOperation
// 創(chuàng)建NSInvocationOperation對象
- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;
// 調(diào)用start方法開始執(zhí)行操作
- (void)start;
// 一旦執(zhí)行操作帚屉,就會調(diào)用target的sel方法
// 默認(rèn)情況下壮锻,調(diào)用了start方法后并不會開一條新線程去執(zhí)行操作,而是在當(dāng)前線程同步執(zhí)行操作,只有將NSOperation放到一個NSOperationQueue中涮阔,才會異步執(zhí)行操作
NSBlockOperation
// 創(chuàng)建NSBlockOperation對象
+ (id)blockOperationWithBlock:(void (^)(void))block;
// 通過addExecutionBlock:方法添加更多的操作
- (void)addExecutionBlock:(void (^)(void))block;
// 注意:只要NSBlockOperation封裝的操作數(shù) > 1猜绣,就會異步執(zhí)行操作
NSOperationQueue
NSOperation可以調(diào)用start方法來執(zhí)行任務(wù),但默認(rèn)是同步執(zhí)行的
// 添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;
- (void)addOperationWithBlock:(void (^)(void))block;
最大并發(fā)數(shù)
-(NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
隊(duì)列的取消敬特、暫停掰邢、恢復(fù)
// 取消隊(duì)列的所有操作
- (void)cancelAllOperations;
// 提示:也可以調(diào)用NSOperation的- (void)cancel方法取消單個操作(在內(nèi)存中給刪除了)
// 暫停和恢復(fù)隊(duì)列
- (void)setSuspended:(BOOL)b; // YES代表暫停隊(duì)列,再設(shè)置為NO代表恢復(fù)之前的隊(duì)列
- (BOOL)isSuspended;
操作優(yōu)先級
- (NSOperationQueuePriority)queuePriority;
- (void)setQueuePriority:(NSOperationQueuePriority)p;
// 優(yōu)先級的取值
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
互斥鎖使用格式
@synchronized(鎖對象) { 需要鎖定的代碼 }