iOS技术

IOS 基础面试题--GCD线程相关类

2016-06-15  本文已影响1043人  MrRightGen
1. 进程与线程
2. 线程相关
3. GCD的三种队列类型

GCD编程的核心就是dispatch队列, dispatch block 的执行最终都会放到某个队列中去进行

4.The main queue(主线程串行队列)

dispatch_sync 同步执行任务函数,不会开启新的线程,dispatch_async 异步执行任务函数,会开启新的线程

  1. 获取主线程串行队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

2.主线程串行队列同步执行任务,在主线程运行时,会产生死锁

 dispatch_queue_t mainQueue = dispatch_get_main_queue();
dispatch_sync(mainQueue,^{
NSLog("MainQueue");            
});

程序一直处于等待状态,block中的代码将执行不到

3.主线程串行队列异步执行任务,在主线程运行,不会产生死锁。

  dispatch_queue_t mainQueue = dispatch_get_main_queue();
  dispatch_async(mainQueue,^{
  NSLog("MainQueue");            
});

程序正常运行,block中的代码正常运行

4.从子线程,异步返回主线程更新UI<这种使用方式比较多>

dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(globalQueue, ^{
//子线程异步执行下载任务,防止主线程卡顿
NSURL *url = [NSURL URLWithString:@"http://www.baidu.com"];
NSError *error;
NSString *htmlData = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (htmlData != nil) {
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
     //异步返回主线程,根据获取的数据,更新UI
    dispatch_async(mainQueue, ^{
        NSLog(@"根据更新UI界面");
    });
} else {
    NSLog(@"error when download:%@",error);
}
});

主线程串行队列由系统默认生成的,所以无法调用dispatch_resume()和dispatch_suspend()来控制执行继续或中断。

5. Global queue (全局并发队列)

耗时的操作,比如读取网络数据,IO,数据库读写等, 我们会在另一个线程中处理这些操作, 然后通知主线程更新界面
1.获取全局并发队列
//程序默认的队列级别,一般不要修改,
DISPATCH_QUEUE_PRIORITY_DEFAULT == 0
dispatch_queue_t globalQueue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //HIGH dispatch_queue_t globalQueue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0); //LOW dispatch_queue_t globalQueue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0); //BACKGROUND dispatch_queue_t globalQueue4 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);

2.全局并发队列同步执行任务,在主线程会导致页面卡顿
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); NSLog(@"current task"); dispatch_sync(globalQueue, ^{ sleep(2.0); NSLog(@"sleep 2.0s"); }); NSLog(@"next task");

依次输出: "current task" "sleep 2.0s","next task",2s之后才会执行block后面的代码,会造成页面卡顿

  1. 全局并发队列异步执行任务,在主线程运行,会开启新的子线程取执行任务,页面不会卡顿
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); NSLog(@"current task"); dispatch_async(globalQueue, ^{ //异步执行,不会等待2s ,造成卡顿 sleep(2.0); NSLog(@"sleep 2.0s"); }); NSLog(@"next task");

4.多个全局并发队列,异步执行任务
dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); NSLog(@"current task"); dispatch_async(globalQueue, ^{ NSLog(@"最先加入全局并发队列"); }); dispatch_async(globalQueue, ^{ NSLog(@"次加入全局并发队列"); }); NSLog(@"next task");
异步线程的执行顺序是不确定的,几乎同步执行,全局并发队列有系统默认生成,,所以无法调用dispatch_resume()和dispatch_suspend()来控制执行继续或中断。

6.自定义队列(custom queue)

1.自定义串行队列

  1. 自定义并发队列
6. 队列组 (Group queue)

当遇到需要多个线程并发执行,然后等多个线程都结束之后,再汇总执行结果时,可以用group queue
1.使用场景: 同时下载多个图片,所有图片下载完成之后,去更新UI (需要回到主线程) 或者去处理其他任务 (可以是其他线程队列)
2.原理: 使用函数 dispatch_group_create 创建 dispatch group , 然后使用函数 dispatch_group_async 来将要执行的block 任务提交到一个 dispatch queue. 同时将他们添加到一个组, 等要执行的block 任务全部执行完毕之后,使用 dispatch_group_notify 函数接收完成时的消息
3.使用示例:
dispatch_queue_t conCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_queue_t mainQueue = dispatch_get_main_queue(); dispatch_group_t groupQueue = dispatch_group_create(); NSLog(@"current task"); dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{ NSLog(@"并行任务1"); }); dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{ NSLog(@"并行任务2"); }); dispatch_group_notify(groupQueue, mainQueue, ^{ NSLog(@"groupQueue中的任务 都执行完成,回到主线程更新UI"); }); NSLog(@"next task");
按此顺序依次输出

4.在当前线程阻塞的同步等待dispatch_group_wait

dispatch_group_t groupQueue = dispatch_group_create();
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC);
dispatch_queue_t conCurrentGlobalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
NSLog(@"current task");
dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{

   long isExecuteOver = dispatch_group_wait(groupQueue, delayTime);
   if (isExecuteOver) {
       NSLog(@"wait over");
   } else {
       NSLog(@"not over");
   }
   NSLog(@"并行任务1");
});
dispatch_group_async(groupQueue, conCurrentGlobalQueue, ^{
   NSLog(@"并行任务2");
});

参数注释:
第一个参数一般是DISPATCH_TIME_NOW,表示从现在开始
第二个参数是延时的具体时间
延时1秒可以写成如下几种:
NSEC_PER_SEC----每秒有多少纳秒
dispatch_time(DISPATCH_TIME_NOW, 1NSEC_PER_SEC);
USEC_PER_SEC----每秒有多少毫秒(注意是指在纳秒的基础上)
dispatch_time(DISPATCH_TIME_NOW, 1000
USEC_PER_SEC); //SEC---毫秒
NSEC_PER_USEC----每毫秒有多少纳秒。
dispatch_time(DISPATCH_TIME_NOW, USEC_PER_SEC*NSEC_PER_USEC);SEC---纳秒

7.GCD中一些系统提供的常用dispatch方法

1.dispatch_after 延时添加到队列
dispatch_time_t delayTime3 = dispatch_time(DISPATCH_TIME_NOW, 3*NSEC_PER_SEC); dispatch_time_t delayTime2 = dispatch_time(DISPATCH_TIME_NOW, 2*NSEC_PER_SEC); dispatch_queue_t mainQueue = dispatch_get_main_queue(); NSLog(@"current task"); dispatch_after(delayTime3, mainQueue, ^{ NSLog(@"3秒之后添加到队列"); }); dispatch_after(delayTime2, mainQueue, ^{ NSLog(@"2秒之后添加到队列"); }); NSLog(@"next task");
dispatch_after 只是延时提交block,并不是延时后立即执行,并不能做到精准控制

  1. dispatch_once 保证在app运行期间,block中的代码只执行一次
    经典使用场景--单例
    //GCD实现单例功能
    + (ShareManager *)shareManager
    {
    static ShareManager *sharedManager = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
    sharedManager = [[self alloc] init];
    });
    return sharedManager;
    }
    @end
    ShareManager的使用
    #######import "ShareManager.h"
    在需要使用的函数中,直接调用下面的方法
    ShareManager *share = [ShareManager shareManager];
    NSLog(@"share is %@",share.someProperty);

最近在学习多线程与GCD的使用,看了很多资料,感觉本文写的比较详细,故引用之.参考自dullgrass-简书

上一篇下一篇

猜你喜欢

热点阅读