提到IOS的多线程,很多人会想到GCD。确实,线程只是GCD其中一部分,它还包括队列,同步,异步等。正因为有几种类型的组合,很多人都比较容易混淆。相信很多人用得比较多的只是:
//使用子线程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//子线程的操作
});
把队列和同异步分开来,就比较好理解:
队列:所有要处理的事件,一个个放到队列里面。根据出列方式的不同,又分为串行队列和并行队列。
串行队列(DISPATCH_QUEUE_SERIAL):是处理完一个事件再出列一个事件。
并行队列(DISPATCH_QUEUE_CONCURRENT):是队列的所有事件一起出来。
同步(sync):会等待处理事件的结果,所以会阻塞当前的线程,不会产生新的子线程。
异步(async):不等待事件的结果,不会阻塞当前线程,会产生新的子线程。
为了更好理解,我做了以下的测试:
1、同步+串行队列
- (void)testThreed1:(NSInteger)tag
{
NSLog(@">>>>>>>>>threed%zi start",tag);
dispatch_sync(_serialQueue, ^{
NSLog(@">>>>>>>>>threed%zi ining isMain=%d",tag,[NSThread currentThread].isMainThread);
sleep(3);
});
NSLog(@">>>>>>>>>threed%zi end",tag);
}
- (void)testSync
{
for(NSInteger i = 0;i<3;i++)
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self testThreed1:i];
});
}
NSLog(@">>>>>>>>end all");
}
执行testSync,结果如下:
2018-08-17 15:41:31.325182+0800 SummaryTest[3324:2499801] >>>>>>>>end all
2018-08-17 15:41:31.325274+0800 SummaryTest[3324:2499905] >>>>>>>>>threed0 start
2018-08-17 15:41:31.325496+0800 SummaryTest[3324:2499905] >>>>>>>>>threed0 ining isMain=0
2018-08-17 15:41:31.325751+0800 SummaryTest[3324:2499913] >>>>>>>>>threed1 start
2018-08-17 15:41:31.337699+0800 SummaryTest[3324:2499906] >>>>>>>>>threed2 start
2018-08-17 15:41:34.330605+0800 SummaryTest[3324:2499905] >>>>>>>>>threed0 end
2018-08-17 15:41:34.330933+0800 SummaryTest[3324:2499913] >>>>>>>>>threed1 ining isMain=0
2018-08-17 15:41:37.336189+0800 SummaryTest[3324:2499913] >>>>>>>>>threed1 end
2018-08-17 15:41:37.336529+0800 SummaryTest[3324:2499906] >>>>>>>>>threed2 ining isMain=0
2018-08-17 15:41:40.338447+0800 SummaryTest[3324:2499906] >>>>>>>>>threed2 end
testSync函数中通过3个异步操作,为的是能尽量同时往串行队列_serialQueue添加事件。然后,给同步处理先入队列的那个事件threed0 ining,处理完成后,下一个事件再出来。所以得到上面的结果。
2、异步+串行队列
- (void)testThreed1:(NSInteger)tag
{
NSLog(@">>>>>>>>>threed%zi start",tag);
dispatch_async(_serialQueue, ^{
NSLog(@">>>>>>>>>threed%zi ining isMain=%d",tag,[NSThread currentThread].isMainThread);
sleep(3);
});
NSLog(@">>>>>>>>>threed%zi end",tag);
}
- (void)testSync
{
for(NSInteger i = 0;i<3;i++)
{
// dispatch_async(dispatch_get_global_queue(0, 0), ^{
// [self testThreed1:i];
// });
[self testThreed1:i];
}
NSLog(@">>>>>>>>end all");
}
结果如下:
2018-08-17 15:50:55.405933+0800 SummaryTest[3327:2501210] >>>>>>>>>threed0 start
2018-08-17 15:50:55.406064+0800 SummaryTest[3327:2501210] >>>>>>>>>threed0 end
2018-08-17 15:50:55.406121+0800 SummaryTest[3327:2501210] >>>>>>>>>threed1 start
2018-08-17 15:50:55.406181+0800 SummaryTest[3327:2501210] >>>>>>>>>threed1 end
2018-08-17 15:50:55.406176+0800 SummaryTest[3327:2501264] >>>>>>>>>threed0 ining isMain=0
2018-08-17 15:50:55.406233+0800 SummaryTest[3327:2501210] >>>>>>>>>threed2 start
2018-08-17 15:50:55.406290+0800 SummaryTest[3327:2501210] >>>>>>>>>threed2 end
2018-08-17 15:50:55.406338+0800 SummaryTest[3327:2501210] >>>>>>>>end all
2018-08-17 15:50:58.410209+0800 SummaryTest[3327:2501264] >>>>>>>>>threed1 ining isMain=0
2018-08-17 15:51:01.415635+0800 SummaryTest[3327:2501264] >>>>>>>>>threed2 ining isMain=0
因为不阻塞了,所以testSync中,我没通过异步添加队列了,不阻塞,循环完成后,队列就添加了3个事件。
3、同步+并行队列
- (void)testThreed1:(NSInteger)tag
{
NSLog(@">>>>>>>>>threed%zi start",tag);
dispatch_sync(_concurrentQueue, ^{
NSLog(@">>>>>>>>>threed%zi ining",tag);
sleep(2);
});
NSLog(@">>>>>>>>>threed%zi end",tag);
}
- (void)testSync
{
for(NSInteger i = 0;i<3;i++)
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self testThreed1:i];
});
}
NSLog(@">>>>>>>>end all");
}
结果如下:
2018-08-17 15:56:43.414786+0800 SummaryTest[3329:2502039] >>>>>>>>end all
2018-08-17 15:56:43.416005+0800 SummaryTest[3329:2502106] >>>>>>>>>threed0 start
2018-08-17 15:56:43.416130+0800 SummaryTest[3329:2502106] >>>>>>>>>threed0 ining
2018-08-17 15:56:43.416294+0800 SummaryTest[3329:2502105] >>>>>>>>>threed1 start
2018-08-17 15:56:43.416354+0800 SummaryTest[3329:2502105] >>>>>>>>>threed1 ining
2018-08-17 15:56:43.416573+0800 SummaryTest[3329:2502104] >>>>>>>>>threed2 start
2018-08-17 15:56:43.416635+0800 SummaryTest[3329:2502104] >>>>>>>>>threed2 ining
2018-08-17 15:56:45.417930+0800 SummaryTest[3329:2502105] >>>>>>>>>threed1 end
2018-08-17 15:56:45.418025+0800 SummaryTest[3329:2502106] >>>>>>>>>threed0 end
2018-08-17 15:56:45.418245+0800 SummaryTest[3329:2502104] >>>>>>>>>threed2 end
可见,2秒后,线程0,1,2几乎是同时结束,说明他们是同时进行处理的。
4、异步+并行
这个就不分析了,平时用的最多。
所以,对于队列和同异步,不要混淆,两个是独立的,相互不影响的。不管你是什么队列,我是同步的,就一直是同步,一直都是阻塞当前线程。
死锁的情况
- (void)deadLock
{
//来个死锁的
NSLog(@">>>>>>>>>start");
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@">>>>>>>>>>in");
});
NSLog(@">>>>>>>>>>end");
}
你可以分析出来原因的。