iOS开发之多线程

iOS开发之多线程

本文章博主和大家一块学习多线程,很自然就涉及到线程和进程,然后涵括NSThread、GCD、NSOperation!然后就是最牛叉的RunLoop和Runtime。

一、线程与进程
进程是对运行时程序的封装,是系统进行资源调度和分配的基本单位,实现了操作系统的并发。
线程是进程的子任务,是CPU调度和分配的基本单位,用于保障程序执行的实时性,实现进程内部的并发。
区别:

  • 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程依赖于进程而存在。
  • 进程是资源分配的最小单位,线程是CPU调度的最小单位
  • 进程在执行过程中拥有独立的内存单元,而多个线程共享进程的内存。
  • 进程间不会相互影响 ;线程:一个线程挂掉将导致整个进程挂掉
  • 线程之间的通信更加方便,同一个进程下线程共享全局变量,静态变量等数据。

二、多线程

多线程的优点和缺点

  • 优点
    1.能适当的提高程序的执行效率
    2.能适当提高资源利用率(CPU内存利用率)
  • 缺点
    1.开启线程需要占用一定的内存空间,如果开启大量的线程,则会占用大量的内存空间,降低程序的性能。
    2.线程越多,CUP在调度线程的开销就越大。
    3.程序设计更加复杂,比如线程之间的通信,多线程的数据共享。

多线程的应用
1.使用单利模式时,可以使用GCD
2.耗时操作放入子线程处理,完成后回主线程显示。
3.从数据库读取大量数据,可开辟子线程操作。
4.处理音频、视频数据时,在子线程处理。
5.数据同步操作。

三、容易混淆的4个术语

同步和异步主要影响:能不能开启新的线程。
1.同步:只是在当前线程中执行任务,不具备开启新线程的能力。
2.异步:可以在新的线程中执行,具备开启新线程的能力。

并发和串行主要影响:任务的执行方式
并发:多个任务并发(同时)执行。
串行:一个任务执行完毕后,再执行下一个任务。

这里写图片描述

四、NSThread、NSOperation、GCD

1.NSThread
1)通过NSThread的对象方法(动态创建)

这里写图片描述

2)通过NSThread的类方法(静态创建)

这里写图片描述
NSThread的线程管理

  1. 线程创建
  2. 线程开启
  3. 线程取消
  4. 线程关闭
  5. 线程暂停
  6. 设置线程优先级

NSThread的线程通信

  1. 指定当前线程执行操作
  2. (在其他线程中)指定主线程执行操作
  3. 在主线程中)指定其他线程执行操作

2.NSOperation
2.1 NSOperation 基本使用
在iOS开发中,为了提升用户体验,我们通常会将操作耗时的操作放在主线程之外的线程进行处理。对于正常的简单操作,我们更多的选择代码更少的GCD,让我们专注于自己的业务逻辑开发。NSOperation在iOS4后也基于GCD实现,但是对于GCD来说可控性更强,并且可以加入操作依赖。
(1) 相关概念
NSOperation是对GCD的封装,其中有两个核心概念【队列+操作】
1.NSOperation本身是抽象类,只能有它的子类。
2.两大子类分别是:NSBlockOperation、NSInvocationOperation,当然你也可以自定义继承自NSOperation的类。

(2)基本使用

  • 实例化NSOperation的子类,绑定执行的操作。
  • 创建NSOperationQueue队列,将NSOperation实例添加进来。
  • 系统会自动将NSOperationQueue队列中检测取出和执行NSOperation的操作。

NSInvocationOperation类

//  01 NSInvocationOperation创建线程
/*
 第一个参数:目标对象
 第二个参数:该操作要调用的方法,最多接受一个参数
 第三个参数:调用方法传递的参数,如果方法不接受参数,那么该值传nil
 */
- (void) method1 {
    NSString * imageUrl = @"https://ss1.bdstatic.com/70cFvXSh_Q1YnxGkpoWK1HF6hhy/it/u=482494819,3150422682&fm=200&gp=0.jpg";
    NSInvocationOperation * invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(loadImageSource:) object:imageUrl];
//    [invocationOperation start];
    //一旦执行操作,就会调用target的sel方法, 默认情况下调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作,只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [queue addOperation:invocationOperation];
}
//更新imageView
- (void)updateImage:(NSData *)data{
    //在主线程中更新UI
    //将二进制数据转换为图片
    UIImage *image=[UIImage imageWithData:data];
    //设置image
    self.imageView.image=image;
}

NSBlockOperation类

  • 创建NSBlockOperation对象
  • 通过addExecutionBlock:方法添加更多的操作
    这里写图片描述

队列的取消、暂停、和恢复

// 恢复队列,继续执行
// self.queue.suspended = NO;

// 暂停(挂起)队列,暂停执行
// self.queue.suspended = YES;

// 取消队列的所有操作
[self.queue cancelAllOperations];

操作依赖

NSOperation之间可以设置依赖来保证执行顺序
这里写图片描述
不添加依赖之前op1、op2、op3的顺序是随机的

在不同queue的NSOperation之间创建依赖关系
这里写图片描述
在不加依赖之前,op1和op2的执行顺序是随机的,添加依赖后op2会在op1之后执行。

线程间的通讯

[[NSOperationQueue mainQueue] addOperationWithBlock:^{
            [self updateImage:data];
        }];

3.GCD

3.1基本概念
全称是Grand Central Dispatch,即:强大的中枢调度器,它是纯C语言的,提供了非常多强大的函数。

3.2GCD的优势:

GCD是苹果公司为多核的并行运算提出的解决方案

GCD会自动利用更多的CPU内核(比如双核、四核)

GCD会自动管理线程的生命周期(创建线程、调度任务、销毁线程)

程序员只需要告诉GCD想要执行什么任务,不需要编写任何线程管理代码

3.3GCD的使用步骤:

  1. 指定任务:确定想要做的事

  2. 将任务添加到队列中:GCD会自动将队列中的任务取出,放到对应的线程中执行,任务的取出遵循队列的FIFO原则:先进先出,后进后出。

3.4GCD的队列

3.4.1 GCD的队列可以分为2大类型:

1.并发队列(Current Dispatch Queue)

2.串行队列(Serial Dispatch Queue)

3.4.2 使用dispatch_queue_create函数创建队列

dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
其中:const char *label 列队列的名称
      dispatch_queue_attr_t attr 队列的类型
创建一个并发队列
    dispatch_queue_t queue1 = dispatch_queue_create("myQueue1", DISPATCH_QUEUE_CONCURRENT);
创建一个串行队列
     dispatch_queue_t queue2 = dispatch_queue_create("myQueue2", DISPATCH_QUEUE_SERIAL);

GCD默认意境提供了全局的并发队列,供整个应用使用,可以无需手动创建

使用dispatch_get_global_queue 函数获得全局并发队列
     //获得全局的并发队列
     dispatch_queue_t queue3 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     其中:第一个参数代表全局并发队列的优先级
     #define DISPATCH_QUEUE_PRIORITY_HIGH 2 --》 高
     #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 --》 默认(中)
     #define DISPATCH_QUEUE_PRIORITY_LOW (-2) --》 低
     #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN --》 后台
     第二个参数标记:是为了未来使用保留的!所以这个参数应该永远指定为0

GCD中获得串行有2种途径

1.使用dispatch_queue_create 创建串行队列,创建串行队列(队列类型传递NULL或者DISPATCH_QUEUE_SERIAL)
     dispatch_queue_t queue4 = dispatch_queue_create("com.520.queue", NULL);
2.使用主队列 (跟主线程相关联的队列),主队列时GCD自带的一种特殊的串行队列,放在主队列中的任务,都会放在主线程中执行,dispatch_get_main_queue()获得主队列
     dispatch_queue_t queue5 = dispatch_get_main_queue();

3.4.3 应用

3.4.3.1 串行队里
3.4.3.2.并发队列(Concurrent Dispatch Queue)

//
//  ViewController.m
//  TestThread
//
//  Created by denggaoqiang on 2022/9/10.
//

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self example14];
    
}

- (void)example1 {
    
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"当前同步任务1一-------%@",[NSThread currentThread]);
        sleep(3);
        
    });
    NSLog(@"1111");
    dispatch_sync(queue, ^{
        NSLog(@"当前同步任务2一-------%@",[NSThread currentThread]);
        sleep(2);
        
    });
    NSLog(@"2222");
    dispatch_sync(queue, ^{
        NSLog(@"当前同步任务3一-------%@",[NSThread currentThread]);
        sleep(1);
    });
    NSLog(@"走到这里了");
    /** 打印结果
     当前同步任务1
     1111
     当前同步任务2
     2222
     当前同步任务3
     走到这里了
     */
}

- (void)example2 {
    
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        
        sleep(5);
        NSLog(@"当前异步任务1一-------%@",[NSThread currentThread]);
    });
    NSLog(@"1111");
    dispatch_async(queue, ^{
        
        sleep(2);
        NSLog(@"当前异步任务2一-------%@",[NSThread currentThread]);
    });
    NSLog(@"2222");
    dispatch_async(queue, ^{
        
        sleep(1);
        NSLog(@"当前异步任务3一-------%@",[NSThread currentThread]);
    });
    NSLog(@"走到这里了");
    /** 打印结果
     
     1111
     2222
     走到这里了
     当前异步任务1
     当前异步任务2
     当前异步任务3
     
     */
}

- (void)example3 {
    
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        sleep(3);
        NSLog(@"当前同步任务1一-------%@",[NSThread currentThread]);
    });
    NSLog(@"1111");
    dispatch_async(queue, ^{
        NSLog(@"当前异步任务2开始一-------%@",[NSThread currentThread]);
        sleep(10);
        NSLog(@"当前异步任务2结束一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"2222");
    
    dispatch_sync(queue, ^{
        sleep(2);
        NSLog(@"当前同步任务3一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"3333");
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"当前异步任务4一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"走到这里了");
    /** 打印结果
     当前同步任务1
     1111
     2222
     当前异步任务2开始
     当前异步任务2结束
     当前同步任务3
     3333
     走到这里了
     当前异步任务4
     */
}

- (void)example4 {
    
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        sleep(5);
        NSLog(@"当前同步任务1一-------%@",[NSThread currentThread]);
    });
    NSLog(@"1111");
    dispatch_sync(queue, ^{
        sleep(3);
        NSLog(@"当前同步任务2一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"2222");
    dispatch_sync(queue, ^{
        sleep(1);
        NSLog(@"当前同步任务3一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"走到这里了");
    /** 打印结果
     当前同步任务1
     1111
     当前同步任务2
     2222
     当前同步任务3
     走到这里了
     */
}

- (void)example5 {
    
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        sleep(5);
        NSLog(@"当前同步任务1一-------%@",[NSThread currentThread]);
    });
    NSLog(@"1111");
    dispatch_async(queue, ^{
        sleep(8);
        NSLog(@"当前异步任务2一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"2222");
    dispatch_async(queue, ^{
        sleep(3);
        NSLog(@"当前同步任务3一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"3333");
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"当前异步任务4一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"走到这里了");
    /** 打印结果
     1111
     2222
     3333
     走到这里了
     当前异步任务4
     当前异步任务3
     当前异步任务1
     当前异步任务2
     */
}

- (void)example6 {
    
    dispatch_queue_t queue = dispatch_queue_create("queueName", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        sleep(3);
        NSLog(@"当前同步任务1一-------%@",[NSThread currentThread]);
    });
    NSLog(@"1111");
    dispatch_async(queue, ^{
        sleep(8);
        NSLog(@"当前异步任务2一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"2222");
    dispatch_sync(queue, ^{
        sleep(3);
        NSLog(@"当前同步任务3一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"3333");
    dispatch_async(queue, ^{
        sleep(1);
        NSLog(@"当前异步任务4一-------%@",[NSThread currentThread]);
        
    });
    NSLog(@"走到这里了");
    /** 打印结果
     当前同步任务1
     1111
     2222
     当前同步任务3
     3333
     走到这里了
     当前异步任务4
     当前异步任务2
     */
}

/**总结:
 一、在同一串行队列种
 同步里面创建同步 死锁崩溃
 同步里面创建异步 正常
 异步里面创建同步 死锁崩溃
 异步里面创建异步 正常
 二、在同一并发队列
 同步里面创建同步 正常
 同步里面创建异步 正常
 异步里面创建同步 正常
 异步里面创建异步 正常
 */

-(void)example71 {
    
    //串行队列   同步里面创建同步 死锁崩溃
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"任务1...");
        NSLog(@"%@", [NSThread currentThread]);
        dispatch_sync(queue, ^{
            NSLog(@"任务2...");
            NSLog(@"%@", [NSThread currentThread]);
        });
        NSLog(@"走到这里了");
    });
    NSLog(@"结束");
    
}

-(void)example72 {
    
    //串行队列   同步里面创建异步 正常
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"任务1...");
        NSLog(@"%@", [NSThread currentThread]);
        dispatch_async(queue, ^{
            NSLog(@"任务2...");
            NSLog(@"%@", [NSThread currentThread]);
        });
        NSLog(@"走到这里了");
    });
    NSLog(@"结束");
    
}

-(void)example73 {
    
    //串行队列   异步里面创建同步 死锁崩溃
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"任务1...");
        NSLog(@"%@", [NSThread currentThread]);
        dispatch_sync(queue, ^{
            NSLog(@"任务2...");
            NSLog(@"%@", [NSThread currentThread]);
        });
        NSLog(@"走到这里了");
    });
    NSLog(@"结束");
}

-(void)example74 {
    
    //串行队列   异步里面创建异步 正常
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"任务1...");
        NSLog(@"%@", [NSThread currentThread]);
        dispatch_async(queue, ^{
            NSLog(@"任务2...");
            NSLog(@"%@", [NSThread currentThread]);
        });
        NSLog(@"走到这里了");
    });
    NSLog(@"结束");
    
}

-(void)example81 {
    
    //并发队列   同步里面创建同步 正常
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        sleep(3);
        NSLog(@"任务1...");
        NSLog(@"%@", [NSThread currentThread]);
        dispatch_sync(queue, ^{
            sleep(1);
            NSLog(@"任务2...");
            NSLog(@"%@", [NSThread currentThread]);
        });
        NSLog(@"走到这里了");
    });
    NSLog(@"结束");
    
}

-(void)example82 {
    
    //并发队列   同步里面创建异步 正常
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_sync(queue, ^{
        sleep(3);
        NSLog(@"任务1...");
        NSLog(@"%@", [NSThread currentThread]);
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"任务2...");
            NSLog(@"%@", [NSThread currentThread]);
            NSLog(@"走到这里了");
        });
    });
    NSLog(@"结束");
}

-(void)example83 {
    
    //并发队列   异步里面创建同步 正常
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        sleep(3);
        NSLog(@"任务1...");
        NSLog(@"%@", [NSThread currentThread]);
        dispatch_sync(queue, ^{
            sleep(1);
            NSLog(@"任务2...");
            NSLog(@"%@", [NSThread currentThread]);
        });
        NSLog(@"走到这里了");
    });
    NSLog(@"结束");
}

-(void)example84 {
    
    //并发队列  异步里面创建异步 正常
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        sleep(3);
        NSLog(@"任务1...");
        NSLog(@"%@", [NSThread currentThread]);
        dispatch_async(queue, ^{
            sleep(1);
            NSLog(@"任务2...");
            NSLog(@"%@", [NSThread currentThread]);
            NSLog(@"走到这里了");
        });
    });
    NSLog(@"结束");
}

-(void)example91{
    
    //任务1和任务2在同一个线程里,在不同的队列里面,可以同步执行 运行正常
    dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue1, ^{
        NSLog(@"%@", [NSThread currentThread]);
        NSLog(@"任务1...");
        dispatch_sync(queue2, ^{
            NSLog(@"%@", [NSThread currentThread]);
            NSLog(@"任务2...");
        });
        NSLog(@"走到这里了");
    });
    NSLog(@"结束");
    
}

-(void)example92{
    
    //任务1和任务2在两个不同线程里,并且两个不同队列,不会造成死锁 可以正常运行
    dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_SERIAL);
    dispatch_queue_t queue2 = dispatch_queue_create("queue2", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue1, ^{
        NSLog(@"%@", [NSThread currentThread]);
        NSLog(@"任务1...");
        dispatch_async(queue2, ^{
            NSLog(@"%@", [NSThread currentThread]);
            NSLog(@"任务2...");
        });
        NSLog(@"走到这里了");
    });
    NSLog(@"结束");
    
}

-(void)example10 {
    //异步串行group
    //创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.sccc", DISPATCH_QUEUE_SERIAL);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue, ^{
        [self doSomething:^() {
            NSLog(@"任务一");
        }];
    });
    dispatch_group_async(group, queue, ^{
        [self doSomething:^() {
            NSLog(@"任务二");
        }];
    });
    dispatch_group_async(group, queue, ^{
        [self doSomething:^() {
            NSLog(@"任务三");
        }];
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"前面的任务已完成");
    });
    
}

-(void)example11 {
    //异步串行group
    //创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.sccc", DISPATCH_QUEUE_CONCURRENT);
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_group_async(group, queue, ^{
        [self doSomething:^() {
            NSLog(@"任务一");
        }];
    });
    dispatch_group_async(group, queue, ^{
        sleep(3);
        [self doSomething:^() {
            NSLog(@"任务二");
        }];
    });
    dispatch_group_async(group, queue, ^{
        
        [self doSomething:^() {
            NSLog(@"任务三");
        }];
    });
    dispatch_group_notify(group, queue, ^{
        NSLog(@"前面的任务已完成");
    });
    
}

- (void)doSomething:(void (^)(void))handler {
    if (handler) {
        sleep(2);
        handler();
    }
}

-(void)example12 {
    
    // 因为 dispatch_group_async 里面的任务是异步的,所以任务在执行的时候,它不会去等待 for 循环执行结束,它会直接跳过 dispatch_async 这 block 执行下一句去了,所以 dispatch_group_notify 也会很快就执行。
    
    
    // 创建一个group
    dispatch_group_t group = dispatch_group_create();
    // 创建一个队列:全局队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    // 将任务1添加到 group 中
    dispatch_group_async(group, queue, ^{
        // 模拟异步网络请求
        sleep(5);
        NSLog(@"任务一完成");
    });
    
    // 将任务2添加到 group 中
    dispatch_group_async(group, queue, ^{
        // 模拟异步网络请求
        sleep(3);
        NSLog(@"任务二完成");
    });
    
    // 任务1和任务2执行结束,回调
    dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"完成任务");
        });
    });
    
    
    
}

-(void)example13 {
    // 创建一个group
    dispatch_group_t group = dispatch_group_create();
    // 创建一个队列:全局队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    // 进入group
    dispatch_group_enter(group);
    
    // 模拟异步网络请求
    dispatch_async(queue, ^{
        
        sleep(3);
        // 离开group
        NSLog(@"任务一完成");
        dispatch_group_leave(group);
        
        
    });
    
    // 进入group
    dispatch_group_enter(group);
    
    // 模拟异步网络请求
    dispatch_async(queue, ^{
        
        sleep(4);
        // 离开group
        NSLog(@"任务二完成");
        dispatch_group_leave(group);
        
        
    });
    
    
    dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"完成任务");
        });
    });
    
}

-(void)example14{
    // 创建一个group
    dispatch_group_t group = dispatch_group_create();
    // 创建一个队列:全局队列
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    
    // 创建信号量,并且设置值为0
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    
    // 将任务1添加到 group 中
    dispatch_group_async(group, queue, ^{
        
        // 模拟异步网络请求
        dispatch_async(queue, ^{
            sleep(3);
            NSLog(@"任务一完成");
            
            // 每次发送信号则 semaphore 会 +1
            dispatch_semaphore_signal(semaphore);
            
        });
        // 由于是异步执行的,当 semaphore 等于 0,则会阻塞当前线程,直到执行了 block 的 dispatch_semaphore_signal,semaphore + 1,才会继续执行。
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
    });
    
    // 将任务2添加到 group 中
    dispatch_group_async(group, queue, ^{
        
        // 模拟异步网络请求
        dispatch_async(queue, ^{
            sleep(3);
            NSLog(@"任务二完成");
            
            dispatch_semaphore_signal(semaphore);
            
        });
        
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
    });
    
    
    dispatch_group_notify(group, queue, ^{
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"完成任务");
        });
    });
    
    
}

@end

3.4.3.3.线程间的通信

  • Direct messaging:这是大家非常熟悉的**-performSelector:系列**。
  • Global variables…:直接通过全局变量、共享内存等方式,但这种方式会造成资源抢夺,涉及到线程安全问题。
  • Conditions:一种特殊的锁–条件锁,当使用条件锁使一个线程等待(wait)时,该线程会被阻塞并进入休眠状态,在另一个线程中对同一个条件锁发送信号(single),则等待中的线程会被唤醒继续执行任务。
  • Run loop sources:通过自定义Run loop sources来实现,后面的文章会单独研究Run loop。
  • Ports and sockets:通过端口和套接字来实现线程间通讯。
  • Run loop:NSMachPort

3.4.3.4.其他应用

1.延时执行
iOS常见三种延时执行方式
1)调用NSObject的方法

 [self performSelector:@selector(需要执行的方法名) withObject:nil afterDelay:2.0]

2)使用GCD函数

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 2秒后执行这里的代码..
    });

3)使用定时器

[NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(需要执行的方法名) userInfo:nil repeats:NO];

2.一次性代码

 static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
       //里面的代码只会被执行一次
    });

3.队列组

有这么一个需求,首先:分别异步执行2个耗时的操作,其次:等2个异步操作都执行完毕后,再回到主线程执行操作,如果想要快速高效地实现上述需求,可以考虑用队列组。

    dispatch_group_tgroup =  dispatch_group_create();  
      
    dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
      
        // 执行1个耗时的异步操作  
      
    });  
      
    dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{  
      
        // 执行1个耗时的异步操作  
      
    });  
      
    dispatch_group_notify(group,dispatch_get_main_queue(), ^{  
      
        // 等前面的异步操作都执行完毕后,回到主线程...  
      
    });  

4.快速迭代
我只想说速度非常快,要加一个__block因为block代码默认不能改外面的东西
这里写图片描述

5.barry执行任务函数

在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行。
下面的例子是在添加到队列的任务1、任务2、任务3执行完毕后,然后才执行barrier,barrier执行完毕后才执行任务4、任务5。
这里写图片描述

dispatch_barrier在并发队列中创建一个同步点,当并发队列中遇到一个 dispatch_barrier时,会延时执行该 dispatch_barrier,等待在 dispatch_barrier之前提交的任务block执行完后才开始执行,之后,并发队列继续执行后续block任务。

6.GCD与定时器

@property (nonatomic,strong) dispatch_source_t timer;
- (void) myTimer {
    self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    // 设置定时器的触发时间(1秒后)和时间间隔(每隔2秒)
    dispatch_source_set_timer(self.timer, dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC), 2 * NSEC_PER_SEC, 0);
    // 设置回调
    dispatch_source_set_event_handler(self.timer, ^{
        NSLog(@"Timer %@", [NSThread currentThread]);
    });
    // 开始定时器
    dispatch_resume(self.timer);
}

-(void)viewDidDisappear:(BOOL)animated {
    dispatch_cancel(self.timer);
    self.timer = nil;
}

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值