iOS多线程开发-GCD的使用

1.多线程相关的几个概念

1.1 任务

任务:就是执行操作的意思,换句话说就是你在线程中执行的那段代码。在GCD中是放在block中的。执行任务有两种方式:同步执行和异步执行。两者的主要区别是是否具备开启新线程的能力。

  • 同步:不具备开启新线程的能力,只能在当前线程中执行任务。
  • 异步:具备开启新线程的能力,可以在新的线程中执行任务。
    注意:异步任务具备开启新线程能力,仅仅表示有这个能力,但是不一定会开启新的线程,下面会详细说明各种情况。
1.2 队列

队列:这里的队列指任务队列,即用来存放任务的队列。队列是一种特殊的线性表,采用FIFO(先进先出)的原则,即新任务总是被插入到队列的末尾,而读取任务的时候总是从队列的头部开始读取。每读取一个任务,则从队列中释放一个任务。在GCD中有两种队列:串行队列并行队列

  • 串行队列:队列中的任务是一个接一个的执行,按照FIFO的原则,先添加的任务先执行
  • 并行队列:队列中的任务可以同时(并行)执行

2.GCD的使用

2.1 获取队列的几种方式
  1. 获取系统主线程中的主队列(串行队列)
	//获取主队列
	dispatch_queue_main_t mainQ = dispatch_get_main_queue();
  1. 获取系统提供的全局队列(并行队列)
	//获取全局并行队列
	dispatch_queue_global_t globalQ = dispatch_get_global_queue(0, 0);
  1. 创建串行队列
	//创建串行队列
	dispatch_queue_t serialQ = dispatch_queue_create("com.example.serial", DISPATCH_QUEUE_SERIAL);
  1. 创建并行队列
	//创建并行队列
	dispatch_queue_t concurrentQ = dispatch_queue_create("com.example.concurrent", DISPATCH_QUEUE_CONCURRENT);
2.2 任务创建的方式
  • 同步执行
    dispatch_queue_global_t queue = dispatch_get_global_queue(0, 0);
    dispatch_sync(queue, ^{
        // 执行任务的代码写这里
    });
  • 异步执行
    dispatch_queue_global_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        // 执行任务的代码写这里
    });
2.3 任务和队列的组合方式
并行队列串行队列主队列
同步执行
异步执行可以开启多条新线程只能开启一条新线程

"否" 表示不能开启新线程

代码论证

	//获取主队列
	dispatch_queue_main_t mainQ = dispatch_get_main_queue();
	//创建串行队列
	dispatch_queue_t serialQ = dispatch_queue_create("com.example.serial", DISPATCH_QUEUE_SERIAL);
	//创建并行队列
	 dispatch_queue_t concurrentQ = dispatch_queue_create("com.example.concurrent", DISPATCH_QUEUE_CONCURRENT);
  • 同步 + 并行
    dispatch_sync(concurrentQ, ^{
        NSLog(@"---------任务1--------%@",[NSThread currentThread]);
    });
    dispatch_sync(concurrentQ, ^{
        NSLog(@"---------任务2--------%@",[NSThread currentThread]);
    });
    dispatch_sync(concurrentQ, ^{
        NSLog(@"---------任务3--------%@",[NSThread currentThread]);
    });
	//    ---------任务1--------<NSThread: 0x600002b140c0>{number = 1, name = main}
	//    ---------任务2--------<NSThread: 0x600002b140c0>{number = 1, name = main}
	//    ---------任务3--------<NSThread: 0x600002b140c0>{number = 1, name = main}
  • 同步 + 串行
    dispatch_sync(serialQ, ^{
        NSLog(@"---------任务1--------%@",[NSThread currentThread]);
    });
    dispatch_sync(serialQ, ^{
        NSLog(@"---------任务2--------%@",[NSThread currentThread]);
    });
    dispatch_sync(serialQ, ^{
        NSLog(@"---------任务3--------%@",[NSThread currentThread]);
    });
    //    ---------任务1--------<NSThread: 0x600002b140c0>{number = 1, name = main}
    //    ---------任务2--------<NSThread: 0x600002b140c0>{number = 1, name = main}
    //    ---------任务3--------<NSThread: 0x600002b140c0>{number = 1, name = main}
  • 同步 + 主队列
    dispatch_async(serialQ, ^{
        dispatch_sync(mainQ, ^{
             NSLog(@"---------任务1--------%@",[NSThread currentThread]);
         });
         dispatch_sync(mainQ, ^{
             NSLog(@"---------任务2--------%@",[NSThread currentThread]);
         });
         dispatch_sync(mainQ, ^{
             NSLog(@"---------任务3--------%@",[NSThread currentThread]);
         });
        //    ---------任务1--------<NSThread: 0x600002b140c0>{number = 1, name = main}
        //    ---------任务2--------<NSThread: 0x600002b140c0>{number = 1, name = main}
        //    ---------任务3--------<NSThread: 0x600002b140c0>{number = 1, name = main}
    });
  • 异步 + 并行
	dispatch_async(concurrentQ, ^{
        NSLog(@"---------任务1--------%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQ, ^{
        NSLog(@"---------任务2--------%@",[NSThread currentThread]);
    });
    dispatch_async(concurrentQ, ^{
        NSLog(@"---------任务3--------%@",[NSThread currentThread]);
    });
    //    ---------任务1--------<NSThread: 0x600000075100>{number = 7, name = (null)}
    //    ---------任务2--------<NSThread: 0x60000007a800>{number = 3, name = (null)}
    //    ---------任务3--------<NSThread: 0x600000001ac0>{number = 4, name = (null)}
    
  • 异步 + 串行
	dispatch_async(serialQ, ^{
        NSLog(@"---------任务1--------%@",[NSThread currentThread]);
    });
    dispatch_async(serialQ, ^{
        NSLog(@"---------任务2--------%@",[NSThread currentThread]);
    });
    dispatch_async(serialQ, ^{
        NSLog(@"---------任务3--------%@",[NSThread currentThread]);
    });
    //    ---------任务1--------<NSThread: 0x6000038f5740>{number = 5, name = (null)}
    //    ---------任务2--------<NSThread: 0x6000038f5740>{number = 5, name = (null)}
    //    ---------任务3--------<NSThread: 0x6000038f5740>{number = 5, name = (null)}
  • 异步 + 主队列
	dispatch_async(mainQ, ^{
        NSLog(@"---------任务1--------%@",[NSThread currentThread]);
    });
    dispatch_async(mainQ, ^{
        NSLog(@"---------任务2--------%@",[NSThread currentThread]);
    });
    dispatch_async(mainQ, ^{
        NSLog(@"---------任务3--------%@",[NSThread currentThread]);
    });
    //    ---------任务1--------<NSThread: 0x600001b08ec0>{number = 1, name = main}
    //    ---------任务2--------<NSThread: 0x600001b08ec0>{number = 1, name = main}
    //    ---------任务3--------<NSThread: 0x600001b08ec0>{number = 1, name = main}
2.3 GCD的应用
  1. dispatch_after
    用于指定时间之后执行任务
	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"3秒钟过后执行");
    });
  1. dispatch_barrier
    异步并行执行任务是无序的,有时候需要控制他们的执行顺序,可以使用
    dispatch_queue_t queue = dispatch_queue_create("com.example.concurrent", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"1-------%@",[NSThread currentThread]);
        for (int i=0; i<3; i++) {
            NSLog(@"1----❤️-----%d",i);
        }
    });
    dispatch_async(queue, ^{
        NSLog(@"2-------%@",[NSThread currentThread]);
        for (int i=0; i<3; i++) {
            NSLog(@"2----😁-----%d",i);
        }
    });
    
    dispatch_barrier_sync(queue, ^{
        NSLog(@"3-------%@",[NSThread currentThread]);
        for (int i=0; i<3; i++) {
            NSLog(@"3----你的心像一道墙-----%d",i);
        }
    });
    dispatch_async(queue, ^{
        NSLog(@"4-------%@",[NSThread currentThread]);
        for (int i=0; i<3; i++) {
            NSLog(@"4----🤖-----%d",i);
        }
    });
  1. dispatch_group_enter、dispatch_group_leave
    当有多个网络请求同时发送的时候,希望所有请求回调都结束再处理一些逻辑,可以使用 dispatch_group_enter、dispatch_group_leave
	dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_group_t group = dispatch_group_create();
    
    // 当有多个网络请求同时发送的时候,希望所有请求回调都结束再处理一些逻辑,可以使用 dispatch_group_enter、dispatch_group_leave
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 3; i++) {
            sleep(1);        //模拟异步耗时操作
            NSLog(@"async1 ------ %ld ----- %@",i,[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 3; i++) {
            sleep(1);        //模拟异步耗时操作
            NSLog(@"async2 ------ %ld ----- %@",i,[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_enter(group);
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 3; i++) {
            sleep(1);        //模拟异步耗时操作
            NSLog(@"async3 ------ %ld ----- %@",i,[NSThread currentThread]);
        }
        dispatch_group_leave(group);
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"终于到我了 --- %@",[NSThread currentThread]);
    });
  1. dispatch_semaphore_t 信号量
    dispatch_semaphore_create(0) 创建一个信号量
    dispatch_semaphore_wait 信号量减1
    dispatch_semaphore_signal 信号量加1
    //创建信号量
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        for (int i=0; i<7; i++) {
            sleep(1.5);
            NSLog(@"----❤️-----%d",i);
        }
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        for (int i=0; i<7; i++) {
            sleep(1.5);
            NSLog(@"----🤩-----%d",i);
        }
        dispatch_semaphore_signal(semaphore);
    });
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        for (int i=0; i<7; i++) {
            sleep(1.5);
            NSLog(@"----🤖-----%d",i);
        }
    });
  1. gcd定时器
    注意:要用一个变量引用 timer ,否则会在方法执行完就释放了。
    @property (nonatomic, strong) dispatch_source_t timer;
    dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    self.timer = timer;// @property (nonatomic, strong) dispatch_source_t timer; 
    // 第二个参数是开始时间,第四个参数是精确度,0表示没有误差
    dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC, 0 * NSEC_PER_SEC);
    dispatch_source_set_event_handler(timer, ^{
        NSLog(@"123123123");
    });
    
    dispatch_resume(timer);

3.多线程常见面试题

3.1 进程和线程的概念?

进程: 在iOS中,可以看做一个正在运行的程序,一个app只能有一个进程。
线程: 线程是进程的基本执行单元,作用是执行进程中的代码,一个进程最少有一个线程,叫做主线程。

3.2 同步和异步的区别?

同步不具备开启新线程的能力,异步具备开启新线程的能力。

3.3 多线程的原理?

单核CPU同一时刻只能处理1条线程,只有1条线程在工作(执行),多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换),如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象

3.4 什么情况下会造成死锁?

在当前串行队列所在的线程中,同步的向当前串行队列添加一个新的任务,就会产生死锁。
例如: 在主线程中,同步向主队列中添加一个任务就会造成死锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值