美文网首页
NSThread/NSOperationQueue/GCD 多线

NSThread/NSOperationQueue/GCD 多线

作者: 可乐小子 | 来源:发表于2016-03-25 15:24 被阅读104次

    什么是线程?什么是主线程?什么是子线程?

    在我们程序运行期间,每个正在运行的代码段,被称为线程。

    程序运行期间,至少有一个线程,该线程为主线程,主要负责刷新UI,比如添加控件,删除控件,更新控件等。

    如果遇到耗时的功能,程序中有多个线程,除了主线程,其余的都是子线程。

    子线程主要负责,耗时的任务,比如,网络请求,处理大数据等。

    iOS 如果遇到多个耗时的任务,或者要求,多个任务同时执行。我们可以使用多线程编程技术,开辟多个线程,把任务放到其他进程中执行。

    线程与线程之间独立执行,互不干扰。

    //iOS 中多线程方式

    一,NSTread   线程类

      1,使用线程类,来开辟线程

     二,NSobject分类方法

     使用场景:只想要一个操作,在开辟的子线程中执行。

    [self performSelectorInBackground:@selector(printString;)  withObject:@"分类开辟子线程方法"];

    [self performSelectorInBackground:@selector(printString;)  withObject:@"分类开辟子线程方法1"];

    [self performSelectorInBackground:@selector(printString;)  withObject:@"分类开辟子线程方法2"];

    [self performSelectorInBackground:@selector(printString;)  withObject:@"分类开辟子线程方法3"];

    // 在主线程中执行SEL方法,传递参数,方法执行结束之前是否等待    yes 等待  ,no不等待

    // @"111"是作为参数传递进 方法printString: 

    [self performSelectorOnMainThread:@selector(printString:) withObject:@"111" waitUntilDone:YES];

    主线程主要用来接受用户相应的操作,更新UI,因此,我们添加UI,更新UI,以及删除UI的操作,一定要放在主线程中执行。比如:label.text = @"aaa";


    // 四 , GCD

    GCD属于函数级别的多线程,主要是分配不同功能的队列,提供给用户使用。

    因此,我们在使用GCD时,根据需求,选用不同功能的队列解决问题。

    //1. gcd 串行队列

    - (IBAction)serialQueue:(id)sender

    //  何时使用: 当多个任务具有依赖关系的时候。

    // 比如:处理用户输入-》网络请求-》处理请求结果 -》登录

    //1.创建一个串行队列

    dispatch_queue_t queue = dispatch_queue_create("queue",DISPATCH_QUEUE_SERIAL);

    //2.添加任务,任务只能是block或者是函数类型

    // 两个参数,前面一个是队列名,后面是添加的任务,代码块block

    dispatch_async(queue,^{

    NSLog(@"%@",[NSThread currentThread];

    NSLog(@"I was borned");

    });

    dispatch_async(queue,^{

    NSLog(@"%@",[NSThread currentThread];

    NSLog(@"i growed");

    });

    dispatch_async(queue,^{

    NSLog(@"%@",[NSThread currentThread];

    NSLog(@"I married");

    });

    dispatch_async(queue,^{

    NSLog(@"%@",[NSThread currentThread];

    NSLog(@"You were dead");

    });

    // 2.全局串行队列是main函数执行所在的主线程的队列,我们称为主队列。主队列是一个全局串行队列,便于用户访问

    // 获取主队列

    dispatch_queue_t mainQueue = dispatch_get_main_queue();

    // 给主队列添加刷新UI的操作

    dispatch_async(mainQueue,^{

    self.view.backgroundColor = [UIColor redColor];

    });

    // 并行队列  conCurrentQueue

    - (IBAction)conCurrentQueue:(id)sender

    {

    // 并行队列是一种同时可以有多个任务并发执行的队列

    // 使用方式:当多个任务,没有依赖关系,谁先执行,谁后执行,都不重要。

    //1. 创建并行队列

    dispatch_queue_t currentQueue = dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);

    // 2.提交操作

    dispatch_async(currentQueue,^{

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"猴子一 连入游戏");

    }

    dispatch_async(currentQueue,^{

    // block 块内封装的可以是需要执行的任务

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"猴子二 连入游戏");

    }

    dispatch_async(currentQueue,^{

    // block 块内封装的可以是需要执行的任务

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"猴子三 连入游戏");

    }

    }

    // 组提交方式

    - (IBAction)group:(id)sender

    {

    // 什么是组提交方式

    // 某些时候,我们需要把一些操作,归为一类操作,比如,链接操作,读取操作。而链接操作和读取操作中,又有多个操作。此时使用组提交方式。

    //1、创建一个并行队列

    dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);

    //2、创建一个组队列

    dispatch_group_t group1 = dispatch_group_create();

    //3、提交

    dispatch_group_async(group1, queue1, ^{

    NSLog(@"玩家1连入游戏");

    });

    dispatch_group_async(group1, queue1, ^{

    NSLog(@"玩家2连入游戏");

    });

    dispatch_group_async(group1, queue1, ^{

    NSLog(@"玩家3连入游戏");

    });

    dispatch_group_async(group1, queue1, ^{

    NSLog(@"玩家4连入游戏");

    });

    dispatch_group_async(group1, queue1, ^{

    NSLog(@"玩家5连入游戏");

    });

    // 组中通知提交方式,当组中所有其他操作执行完毕后,它才会执行

    dispatch_group_notify(group1,queue1,^{

    NSLog(@"所有玩家接入完毕,游戏开始");

    });

    }

    // barrier 障碍提交方式

    - (IBAction)barrier:(id)sender

    {

    // barrier 提交方式,其实是把多个操作,划分为两个部分,这两个部分执行方式都是并发执行的。

    //  只要多一个barrier 就会划分出来两个部分

    //  通常用于前面有多个操作,后面有多个操作,后面部分要等到前面部分执行完毕再执行

    //1. 并行执行

    dispatch_queue_t queue = dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);

    //2.提交操作

    dispatch_async(queue,^{

    NSLog(@"网络连接成功");

    });

    dispatch_async(queue,^{

    NSLog(@"用户请求成功“);

    });

    dispatch_async(queue,^{

    NSLog(@"验证用户名密码");

    });

    // 障碍提交方式

    dispatch_barrier_async(queue,^{

    NSLog(@"验证完成");

    });

    dispatch_async(queue,^{

    NSLog(@"读取用户数据");

    });

    }

    // after 延迟执行

    - (IBAction)after:(id)after{

    // 延迟执行,多用于加载图,线程睡眠等使用场景

    // 1.从哪个时间点去

    // 2. 过几秒后

    // 3.提交到哪个队列中

    // 4. 执行block

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(5*NSEC_PER_SEC)) , dispatch_get_main_queue(),^{

    self.view.backgroundColor = [UIColor redColor];

    // 延迟五秒,把当前控制器所在的视图的背景颜色换为红色

    });   

    }

    // apply 重复提交执行

    - (IBAction)apply:(id)sender

    {

    // 使用场景:有多个任务,需要提交到队列中时,使用apply方式

    //1. 把多个任务存储到数组中

    NSArray *array = @[@"图片1",@"图片2",@"图片3",@"图片4",@"图片5"];

    //2. 提交到一个并行队列中

    // 参数1. 数组个数,重复执行次数

    // 参数2.提交到哪个队列中

    // 参数3.当前执行的次数

    dispatch_apply(5,dispatch_get_global_queue(0,0),^(size_t i){

    // i从0开始到 5-1

    NSLog(@"%@",array[i]);

    });

    }


    // NSOperationQueue 

    - (IBAction)operationQueue:(id)sender

    {

    // 使用场景,当我们有多个任务,都需要放倒子线程中执行时,使用操作队列这种方式,更为高效,队列内部给我们创建了合适的线程数。

    //  什么是操作队列? 何时使用操作队列?

    // 操作队列事以一个队列,内部提交的是操作对象,队列中可以给我们开辟适当的线程数去解决多个要执行的操作

    // 操作队列是以合适的线程数,更加高效地解决需求

    // 创建操作对象

    NSInvocationOperation *invo1 = [[NSInvovationOperation alloc] initWithTarget:self selector:@selector(printString:) object:@"1111"];

    NSInvocationOperation *invo2 = [[NSInvovationOperation alloc] initWithTarget:self selector:@selector(printString:) object:@"2222"];

    NSInvocationOperation *invo3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(printString:) object:@"333"];

    // 2.以block方式创建对象

    NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{

    // block 内部填写我们要执行的操作,当该操作对象执行时,会调用block,执行操作

    NSLog(@"I");

    }];

    NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{

    // block 内部填写我们要执行的操作,当该操作对象执行时,会调用block,执行操作

    NSLog(@"lOVE");

    }];

    NSBlockOperation *bo3 = [NSBlockOperation blockOperationWithBlock:^{

    //block 内部填写我们要执行的操作,当该操作对象执行时,会调用block,执行操作

    NSLog(@"You");

    }];

    // 1. 创建一个操作队列

    NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];

    // 设置操作队列的最大并发数

    queue1.maxConcurrentOperationCount = 3;

    // 同一时间点,能够执行的操作数

    // 当队列的最大并发数为1时为,串行队列,大于1为并行队列。

    // 如何让并行队列中,某些任务按照顺序执行?

    //  给任务添加依赖关系

    [invo2 addDependency:invo1];

    [invo3 addDependency:invoke];

    //把操作添加到操作队列里面

    //    [queue1 addOperation:invo1];

    //    [queue1 addOperation:invo2];

    //    [queue1 addOperation:invo3];

    //把操作添加到操作队列里面

    [queue1 addOperation:bo1];

    [queue1 addOperation:bo2];

    [queue1 addOperation:bo3];

    }

    - (IBAction)block:(id)sender {

    //  [self printNumber];

    [NSThread detachNewThreadSelector:@selector(printNumber)  toTarget:self withObject:nil];

    }

    - (IBAction)thread:(id)sender {

    //1、开辟一个线程

    // [NSThread detachNewThreadSelector:@selector(printNumber) toTarget:self withObject:nil];

    // 注意: detach 创建的线程,自动执行,通常用于默认执行的操作。

    // 2、NSThread 开辟的线程另一种方法  init

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(printString:) object:@"111" ];

    //初始化方法创建的线程,需要我们手动开启,使用start方法

    [thread start];

    //结束线程

    // [thread cancel];

    NSLog(@"%@ %ld",[NSThread currentThread],[NSThread isMainThread]);

    }

    // 打印一个string

    - (void)printString:(NSString *)string

    {

    NSLog(@"%@ %d %@",[NSThread currentThread ],[NSThread isMainThread],string);

    }

    - (IBAction)cankao:(id)sender {

    NSLog(@"aaaaa");

    }

    //for 循环方法

    - (void)printNumber

    {

    @autoreleasepool {

    for (int i = 0; i < 655000000; i++) {

    NSLog(@"%d",i);

    }

    }

    }

    - (IBAction)sync:(id)sender {

    //同步提交方式会等 提交的操作执行完毕后,再执行后面的操作。

    //同步提交方式会卡主线程。

    dispatch_sync(dispatch_get_global_queue(0, 0), ^{

    NSLog(@"%@",[NSThread currentThread]);

    for (int i = 0; i < 10; i ++) {

    NSLog(@"%d",i);

    }

    });

    NSLog(@"%@",[NSThread currentThread]);

    NSLog(@"我在下面我在下面我在下面");

    dispatch_sync(dispatch_get_global_queue(0, 0), ^{

    NSLog(@"aaaaaaaaa");

    });

    }

    void sum(void *string)

    {

    //注意传递过来的是什么类型就用什么类型打印。

    NSLog(@"%s",string);

    }

    // 提交函数

    - (IBAction)function:(id)sender {

    dispatch_async_f(dispatch_get_main_queue(), "aaa", sum);

    //获取线程名

    dispatch_queue_t queue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);

    const char *name = dispatch_queue_get_label(queue);

    NSLog(@"%@",[NSString stringWithUTF8String:(const char *)name]);

    }

    相关文章

      网友评论

          本文标题:NSThread/NSOperationQueue/GCD 多线

          本文链接:https://www.haomeiwen.com/subject/nijflttx.html