iOS开发中经常会用到多线程的技术,官方提供的多线程api包括pthread、NSThread、GCD和NSOperation;其中pthread是C的接口,对于开发者来说不够友好,NSThread是一个比较简单的api,使用场景有限,GCD是苹果官方提供的系统级的线程管理,api丰富,执行性能高,NSOperation是基于GCD的封装,本篇文章是工作中对于GCD使用的一些总结。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"do something");
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"do some other thing");
});
});
上述代码是GCD最简单的一种用法。子线程进行耗时操作,主线程刷新UI或者做动画,但是GCD的强大远不止这些。dispatch_async和dispatch_sync是block的提交方式,分别代表异步提交和同步提交,队列分为并发队列和串行队列,提交方式和队列的组合有四种场景,如下方表格所示:
并发队列/concurrent | 串行队列/serial | |
---|---|---|
dispatch_async | 并发执行 | 同步执行 |
dispatch_sync | 同步执行效果 | 同步执行效果 |
接下来看一下GCD提供的api:
dispatch_async(dispatch_queue_t queue, dispatch_block_t block):异步提交block进队列的api,提交后会立即返回,不会等待block被执行完,执行队列决定提交进去的block是同步执行还是并发执行。
dispatch_sync(dispatch_queue_t queue, DISPATCH_NOESCAPE dispatch_block_t block):同步提交block进队列的api,提交后不会立即返回,同时会阻塞当前线程,等到block执行完成。切记不可同步提交block进主队列,结果会造成死锁。
dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block):通过该api提交的block,会在该队列完成之前提交的所有的block后才会执行,在这个方法后面的提交的blocks也必须等待当前block执行完才会操作,该api会立即返回,不会阻塞主线程。
dispatch_queue_t aQueue = dispatch_queue_create("com.wanglei.gcddemo.aQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(aQueue, ^{
sleep(2);
NSLog(@"+++++++++++1");
});
dispatch_async(aQueue, ^{
NSLog(@"+++++++++++2");
});
dispatch_barrier_async(aQueue, ^{
sleep(3);
NSLog(@"+++++++++++3");
});
NSLog(@"+++++++++test");
dispatch_async(aQueue, ^{
NSLog(@"+++++++++++4");
});
输出结果如下
2019-04-26 16:58:19.161177+0800 WLTest[15736:1047575] +++++++++test
2019-04-26 16:58:19.161310+0800 WLTest[15736:1047796] +++++++++++2
2019-04-26 16:58:21.166526+0800 WLTest[15736:1049056] +++++++++++1
2019-04-26 16:58:24.167634+0800 WLTest[15736:1049056] +++++++++++3
2019-04-26 16:58:24.167822+0800 WLTest[15736:1049056] +++++++++++4
可见该方法并没有阻塞主线程,任务4也是在barrier任务完成后才执行的。
需要注意的是这里的队列queue不能使用全局队列,必须是自定义的队列。网上有文章指出该api是可以解决多线程并发读写同一个资源时发生死锁的问题,示例代码如下:
@implementation TicketManager
- (instancetype)init {
self = [super init];
if (self) {
self.ticketNumber = 10000;
saleQueue = dispatch_queue_create("com.wanglei.gcddemo.saleQueue", DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
- (void)sale:(int)number {
dispatch_barrier_async(saleQueue, ^{
if (self.ticketNumber == 0) {
NSLog(@"+++++++++++++++++++++票已售罄");
} else {
if (self.ticketNumber >= number) {
self.ticketNumber -= number;
NSLog(@"+++++++++++++++售出%d张++++++++++++++还剩%d张",number,self.ticketNumber);
} else {
NSLog(@"++++++++++++++++++票数不足,无法完成本次交易");
}
}
});
}
@end
dispatch_barrier_sync(dispatch_queue_t queue, dispatch_block_t block):功能与async类似,但是这个会阻塞主线程,不建议使用。
dispatch_queue_t aQueue = dispatch_queue_crea