關(guān)于多線程,在編程中那是必不可少的,現(xiàn)在我們就好好梳理一下多線程.
在 iOS 中其實(shí)目前主要有3套多線程方案道逗,他們分別是:
NSThread
GCD
NSOperation & NSOperationQueue
NSThread
NSThread是經(jīng)過蘋果封裝后的权谁,并且完全面向?qū)ο蟮摹K阅憧梢灾苯硬倏鼐€程對象,非常直觀和方便办悟。
它的生命周期還是需要我們手動(dòng)管理,所以并不推薦使用
//多線程處理
-(void)manyThreadHandle
{
//方法1
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(makerun:) object:@"1"];
// 啟動(dòng)
[thread start];
//方法2? 不用手動(dòng)啟動(dòng) 自動(dòng)啟動(dòng)
[NSThread detachNewThreadWithBlock:^{
NSLog(@"--方法2");
}];
//方法3? 不用手動(dòng)啟動(dòng)自動(dòng)啟動(dòng)
[NSThread detachNewThreadSelector:@selector(makerun:) toTarget:self withObject:@"2"];
}
-(void)makerun:(NSThread*)thred
{
NSLog(@"多線程--%@",thred);
}
2017-08-30 16:01:24.863 runtimeTest[6579:165898] --方法2
2017-08-30 16:01:24.864 runtimeTest[6579:165897] 多線程--1
2017-08-30 16:01:24.864 runtimeTest[6579:165899] 多線程--2
在NSThread 中海油很多方法和屬性
//取消線程
- (void)cancel;
//啟動(dòng)線程
- (void)start;
//判斷某個(gè)線程的狀態(tài)的屬性
@property (readonly, getter=isExecuting) BOOL executing;
@property (readonly, getter=isFinished) BOOL finished;
@property (readonly, getter=isCancelled) BOOL cancelled;
//設(shè)置和獲取線程名字
-(void)setName:(NSString *)n;
-(NSString *)name;
//獲取當(dāng)前線程信息
+ (NSThread *)currentThread;
//獲取主線程信息
+ (NSThread *)mainThread;
//使當(dāng)前線程暫停一段時(shí)間捺氢,或者暫停到某個(gè)時(shí)刻
+ (void)sleepForTimeInterval:(NSTimeInterval)time;
+ (void)sleepUntilDate:(NSDate *)date;
GCD 方法
GCD 這個(gè)名字是不是很霸氣 ,天朝人都懂得.其實(shí)指的是Grand Central Dispatch(GCD)
GCD會(huì)自動(dòng)合理地利用更多的CPU內(nèi)核(比如雙核牵敷、四核),最重要的是它會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程椿息、調(diào)度任務(wù)歹袁、銷毀線程),完全不需要我們管理寝优,我們只需要告訴干什么就行宇攻。同時(shí)它使用的也是c語言,不過由于使用了 Block(Swift里叫做閉包)倡勇,使得使用起來更加方便,而且靈活。這個(gè)方法比較實(shí)用簡便,強(qiáng)烈推薦.
在GCD中妻熊,加入了兩個(gè)非常重要的概念:任務(wù)和隊(duì)列夸浅。
任務(wù)
任務(wù):即操作,你想要干什么扔役,說白了就是一段代碼帆喇,在 GCD 中就是一個(gè) Block,所以添加任務(wù)十分方便亿胸。任務(wù)有兩種執(zhí)行方式:同步執(zhí)行和異步執(zhí)行坯钦,主要區(qū)別在于會(huì)不會(huì)阻塞當(dāng)前線程,直到Block中的任務(wù)執(zhí)行完畢侈玄!
同步執(zhí)行:阻塞當(dāng)前線程,不會(huì)開辟新的線程
異步執(zhí)行:不會(huì)阻塞當(dāng)前線,程會(huì)開辟新的線程
隊(duì)列:用于存放任務(wù)婉刀。一共有兩種隊(duì)列,串行隊(duì)列和并行隊(duì)列序仙。
放到串行隊(duì)列的任務(wù)突颊,GCD 會(huì)FIFO(先進(jìn)先出)地取出來一個(gè),執(zhí)行一個(gè)潘悼,然后取下一個(gè)律秃,這樣一個(gè)一個(gè)的執(zhí)行。簡單說串行 就是單行車道 ,所有的車(任務(wù))都只能按順序走
放到并行隊(duì)列的任務(wù)治唤,GCD 也會(huì)FIFO的取出來棒动,但不同的是,它取出來一個(gè)就會(huì)放到別的線程宾添,然后再取出來一個(gè)又放到另一個(gè)的線程船惨。這樣由于取的動(dòng)作很快,忽略不計(jì)辞槐,看起來掷漱,所有的任務(wù)都是一起執(zhí)行的。簡單說并行 就是多條車道 ,所有的車(任務(wù))都可以在對應(yīng)車道上走,和隔壁車道沒什么影響
主隊(duì)列? 任何需要刷新 UI 的工作都要在主隊(duì)列執(zhí)行
dispatch_queue_t queue = dispatch_get_main_queue();
自己創(chuàng)建隊(duì)列
//串行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("tk22.bournes.testQueue", NULL);
dispatch_queue_t queue = dispatch_queue_create("tk22.bournes.testQueue", DISPATCH_QUEUE_SERIAL);
//并行隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("tk22.bournes.testQueue", DISPATCH_QUEUE_CONCURRENT);
//全局并行隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
隊(duì)列組
隊(duì)列組可以將很多隊(duì)列添加到一個(gè)組里榄檬,這樣做的好處是卜范,當(dāng)這個(gè)組里所有的任務(wù)都執(zhí)行完了,隊(duì)列組會(huì)通過一個(gè)方法通知我們鹿榜。
//1.創(chuàng)建隊(duì)列組
dispatch_group_t group = dispatch_group_create();
//2.創(chuàng)建隊(duì)列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//多次使用隊(duì)列組的方法執(zhí)行任務(wù), 只有異步方法
//執(zhí)行3次循環(huán)
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 3; i++) {
NSLog(@"group-01 - %@", [NSThread currentThread]);
}
});
//主隊(duì)列執(zhí)行8次循環(huán)
dispatch_group_async(group, dispatch_get_main_queue(), ^{
for (NSInteger i = 0; i < 8; i++) {
NSLog(@"group-02 - %@", [NSThread currentThread]);
}
});
//執(zhí)行10次循環(huán)
dispatch_group_async(group, queue, ^{
for (NSInteger i = 0; i < 10; i++) {
NSLog(@"group-03 - %@", [NSThread currentThread]);
}
});
//4.都完成后會(huì)自動(dòng)通知
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"完成 - %@", [NSThread currentThread]);
});
//運(yùn)行結(jié)果
2017-08-30 16:21:36.201 runtimeTest[6843:174540] group-01 -{number = 3, name = (null)} ? ? ? ? ?2017-08-30 16:21:36.201 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ? 2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ?2017-08-30 16:21:36.202 runtimeTest[6843:174540] group-01 -{number = 3, name = (null)} ? ? ? ? 2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ?2017-08-30 16:21:36.202 runtimeTest[6843:174540] group-01 -{number = 3, name = (null)} ? ? ? ? 2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ?2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ?2017-08-30 16:21:36.202 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ?2017-08-30 16:21:36.203 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ?2017-08-30 16:21:36.203 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ?2017-08-30 16:21:36.203 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ?2017-08-30 16:21:36.203 runtimeTest[6843:174555] group-03 -{number = 4, name = (null)} ? ? ? ?2017-08-30 16:21:36.206 runtimeTest[6843:174502] group-02 -{number = 1, name = main} ? ? ? ? 2017-08-30 16:21:36.207 runtimeTest[6843:174502] group-02 -{number = 1, name = main} ? ? ? ? ?2017-08-30 16:21:36.207 runtimeTest[6843:174502] group-02 -{number = 1, name = main} ? ? ? ? ?2017-08-30 16:21:36.207 runtimeTest[6843:174502] group-02 -{number = 1, name = main} ? ? ? ? ?2017-08-30 16:21:36.207 runtimeTest[6843:174502] group-02 -{number = 1, name = main} ? ? ? ? ?2017-08-30 16:21:36.208 runtimeTest[6843:174502] group-02 -{number = 1, name = main} ? ? ? ? 2017-08-30 16:21:36.208 runtimeTest[6843:174502] group-02 -{number = 1, name = main} ? ? ? ? 2017-08-30 16:21:36.208 runtimeTest[6843:174502] group-02 -{number = 1, name = main} ? ? ? ? ?2017-08-30 16:21:36.209 runtimeTest[6843:174502] 完成 -{number = 1, name = main}
NSOperation和NSOperationQueue
NSOperation 是蘋果公司對 GCD 的封裝海雪,完全面向?qū)ο螅允褂闷饋砀美斫?有很多和GCD比較類似
NSOperation 和 NSOperationQueue分別對應(yīng) GCD 的任務(wù) 和 隊(duì)列
NSOperation只是一個(gè)抽象類舱殿,所以不能封裝任務(wù)它有 2 個(gè)子類用于封裝任務(wù)奥裸。分別是:NSInvocationOperation和NSBlockOperation
當(dāng)你新創(chuàng)建一個(gè) Operation 后,需要手動(dòng)的調(diào)用start方法來啟動(dòng)任務(wù)沪袭,它會(huì)默認(rèn)在當(dāng)前隊(duì)列同步執(zhí)行湾宙。當(dāng)然你也可以在中途取消一個(gè)任務(wù),只需要調(diào)用其cancel方法即可。
//1.創(chuàng)建NSInvocationOperation對象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
//2.開始執(zhí)行
[operation start];
//1.創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//添加多個(gè)Block
for (NSInteger i = 0; i < 5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}
//2.開始任務(wù)
[operation start];
2017-08-30 16:33:12.868 runtimeTest[7014:179819]{number = 1, name = main}
2017-08-30 16:33:12.869 runtimeTest[7014:179819] 第3次:{number = 1, name = main}
2017-08-30 16:33:12.869 runtimeTest[7014:179819] 第4次:{number = 1, name = main}
2017-08-30 16:33:12.868 runtimeTest[7014:179888] 第1次:{number = 4, name = (null)}
2017-08-30 16:33:12.868 runtimeTest[7014:179892] 第0次:{number = 3, name = (null)}
2017-08-30 16:33:12.869 runtimeTest[7014:179889] 第2次:{number = 5, name = (null)}
根據(jù)結(jié)果可以知道打印的順序是亂的 這個(gè)也符合我們異步的任務(wù)執(zhí)行情況
//1.創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//2.開始任務(wù)
[operation start];
創(chuàng)建隊(duì)列
//主隊(duì)列
NSOperationQueue *queue = [NSOperationQueue mainQueue];
//1.創(chuàng)建一個(gè)其他隊(duì)列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//2.創(chuàng)建NSBlockOperation對象
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@", [NSThread currentThread]);
}];
//3.添加多個(gè)Block
for (NSInteger i = 0; i < 2; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@", i, [NSThread currentThread]);
}];
}
//4.隊(duì)列添加任務(wù)
[queue addOperation:operation];
2017-08-30 16:35:56.163 runtimeTest[7073:181494]{number = 3, name = (null)}
2017-08-30 16:35:56.163 runtimeTest[7073:181537] 第0次:{number = 4, name = (null)}
2017-08-30 16:35:56.163 runtimeTest[7073:181538] 第1次:{number = 5, name = (null)}
NSOperation有一個(gè)非常實(shí)用的功能侠鳄,那就是添加依賴 和gcd中的隊(duì)列組管理有點(diǎn)類似.有點(diǎn)啰嗦了,就先介紹這些吧,以后有時(shí)間會(huì)更新.