【iOS进阶】【多线程】1-GCD
一、GCD基本思想
1>GCD的基本思想是就将操作放在队列中去执行
1.操作使用Blocks定义
2.队列负责调度任务执行所在的线程以及具体的执行时间
3.队列的特点是先进先出(FIFO)的,新添加至对列的操作都会排在队尾
4.提示:GCD的函数都是以dispatch(分派、调度)开头的
5.队列:dispatch_queue_t
(1)串行队列,队列中的任务只会顺序执行。DISPATCH_QUEUE_SERIAL
(2)并行队列,队列中的任务通常会并发执行。DISPATCH_QUEUE_CONCURRENT
6.操作
dispatch_async 异步操作,会并发执行,无法确定任务的执行顺序
dispatch_sync 同步操作,会依次顺序执行,能够决定任务的执行顺序
二、GCD基本实现
1>串行队列,DISPATCH_QUEUE_SERIAL
-(void)gcdDemo1{ //将操作放在队列中 //在C语言函数中,定义类型,绝大多数的结尾时_t或者ref dispatch_queue_t q = dispatch_queue_create("cn.itcas.gcddemo", DISPATCH_QUEUE_SERIAL); //异步任务,并发执行。
//使用串行队列,的异步任务非常非常有用
dispatch_async(q, ^{ NSLog(@"%@",[NSThread currentThread]); }); //串行队列的同步任务,同样会在主线程上运行 //实际操作中极少用 //同步任务,顺序执行 dispatch_sync(q, ^{ //[NSThread currentThread] 可以在开发中,跟踪当前线程 //打印的 num = 1,表示主线程。 num = 2,表示第2个子线程 NSLog(@"%@",[NSThread currentThread]); }); }
2>并行队列,DISPATCH_QUEUE_CONCURRENT
#pragma mark 并行(并排跑,类似于赛跑)队列,DISPATCH_QUEUE_CONCURRENT -(void)gcdDemo2{ //特点:没有队形,执行顺序程序员无法控制 //应用场景:并发执行任务,没有先后顺序 dispatch_queue_t q = dispatch_queue_create("cn.itcas.gcd2", DISPATCH_QUEUE_CONCURRENT); //可以调换两个for循环来看看运行结果 /**
异步操作会新建多个线程、操作无序执行(有用,容易出错!)
队列前如果有其他任务,会等待前面的任务完成之后再执行
场景:既不影响主线程,又不需要顺序执行的操作!
*/
for(int i = 0;i<10 ; i++){ //异步任务,在并行队列中,无序 dispatch_async(q, ^{ //[NSThread currentThread] 可以在开发中,跟踪当前线程 //打印的 num = 1,表示主线程。 num = 2,表示第2个子线程 NSLog(@"%@",[NSThread currentThread]); }); } for(int i = 0;i<10 ; i++){ //同步任务,顺序执行 dispatch_sync(q, ^{ //[NSThread currentThread] 可以在开发中,跟踪当前线程 //打印的 num = 1,表示主线程。 num = 2,表示第2个子线程 NSLog(@"%@",[NSThread currentThread]); }); } }
3>全局队列,dispatch_get_global_queue
#pragma mark 全局队列(方便多线程的设计,提供来一个全局队列,供所有的APP共同使用) -(void)gcdDemo3{ //全局队列与并行队列的区别 //1> 不需要创建,直接GET就能用 //2> 两个队列的执行效果相同 //3> 全局队列没有名称,调试时,无法确认准确队列 //记住:开发中永远用DISPATCH_QUEUE_PRIORITY_DEFAULT(默认) dispatch_queue_t q = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //串行队列的同步任务,同样会在主线程上运行 //实际操作中极少用 for(int i = 0;i<10 ; i++){ //同步任务,顺序执行 dispatch_sync(q, ^{ //[NSThread currentThread] 可以在开发中,跟踪当前线程 //打印的 num = 1,表示主线程。 num = 2,表示第2个子线程 NSLog(@"%@",[NSThread currentThread]); }); } for(int i = 0;i<10 ; i++){ //异步任务,并发执行。在串行队列中,仍然会依次顺序执行 dispatch_async(q, ^{ //[NSThread currentThread] 可以在开发中,跟踪当前线程 //打印的 num = 1,表示主线程。 num = 2,表示第2个子线程 NSLog(@"%@",[NSThread currentThread]); }); } }
4>主队列,dispatch_get_main_queue()
#pragma mark 主线程队列,保证操作在主线程上执行 -(void)gcdDemo4{ //每一个应用程序都只有一个主线程 //为什么需要在主线程上工作呢? //在iOS开发中,所有UI的更新工作,都必须在主线程上执行 dispatch_queue_t q = dispatch_get_main_queue(); //主线程是有工作多,除非将程序杀掉,否则主线程多工作不会结束 //主线程不能做同步操作,这样会阻塞! //dispatch_sync(q, ^{ //NSLog(@"%@",[NSThread currentThread]); //}); //主队列中的操作都应该在主线程上顺序执行的,不存在异步的概念 //异步任务在主线程上运行,同样是保持队形的 for(int i = 0;i<10;i++){ dispatch_async(q, ^{ NSLog(@"%@",[NSThread currentThread]); }); } }
5>dispatch_sync的应用场景
//阻塞并行队列的执行,要求某一操作执行后再进行后续操作,如用户登录 //确保块代码之外的局部变量确实被修改 dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_CONCURRENT); __block BOOL logon = NO; dispatch_sync(q, ^{ NSLog(@"模拟耗时操作 %@", [NSThread currentThread]); [NSThread sleepForTimeInterval:2.0f]; NSLog(@"模拟耗时完成 %@", [NSThread currentThread]); logon = YES; }); dispatch_async(q, ^{ NSLog(@"登录完成的处理 %@", [NSThread currentThread]); });
三、GCD小结
1>GCD
1.通过GCD,开发者不用再直接跟线程打交道,只需要向队列中添加代码块即可
2.GCD在后端管理着一个线程池,GCD不仅决定着代码块将在哪个线程被执行,它还根据可用的系统资源对这些线程进行管理。
从而让开发者从线程管理的工作中解放出来,通过集中的管理线程,缓解大量线程被创建的问题
3.使用GCD,开发者可以将工作考虑为一个队列,而不是一堆线程,这种并行的抽象模型更容易掌握和使用
2>GCD的队列
1.GCD公开有5个不同的队列:运行在主线程中的主队列,3 个不同优先级的后台队列,以及一个优先级更低的后台队列(用于 I/O)
2.自定义队列:串行和并行队列。自定义队列非常强大,建议在开发中使用。在自定义队列中被调度的所有Block最终都将被放入到系统
的全局队列中和线程池中
提示:不建议使用不同优先级的队列,因为如果设计不当,可能会出现优先级反转,即低优先级的操作阻塞高优先级的操作
3>GCD队列示意图

浙公网安备 33010602011771号