zoukankan      html  css  js  c++  java
  • iOS中的多线程基础

    NSThread

    NSThread是一个苹果封装过的,面向对象的线程对象。但是它的生命周期需要我们自己来手动管理,所以使用不是很常见,比如[NSThread currentThread],它可以获取当前的线程类,你就可以知道当前线程的各种属性。

    创建并启动

        //1.先创建,再启动
        //创建
        NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(run) object:nil];
        //启动
        [thread start];
        
        //2.创建并自动启动
        [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
        //苹果认为performSelector系列方法不安全,所以在swift中,去掉了这个方法
        [self performSelectorInBackground:@selector(run) withObject:nil];

    NSThread其他常用的方法

        /*
        //3.NSThread的常见方法
        //取消线程
        - (void)cancel;
        //启动线程
        - (void)start;
        //判断某个线程的状态的属性
        @property (readonly, getter=isExecuting) BOOL executing;
        @property (readonly, getter=isFinished) BOOL finished;
        @property (readonly, getter=isCancelled) BOOL cancelled;
        //设置和获取线程名字
        -(void)setName:(NSString *)n;
        -(NSString *)name;
        //获取当前线程信息
        + (NSThread *)currentThread;
        //获取主线程信息
        + (NSThread *)mainThread;
        //使当前线程暂停一段时间,或者暂停到某个时刻
        + (void)sleepForTimeInterval:(NSTimeInterval)time;
        + (void)sleepUntilDate:(NSDate *)date;
         */

    GCD

    Grand Central Dispatch,感觉很强大,当然,它的确很强大。它是苹果公司为多处理器的并行运算提出的解决方案,所以可以自动合理的利用跟多的cpu内核(不懂~~~),GCD可以自动的管理线程的生命周期(创建线程,调度任务,销毁线程),作为程序员,我们不需要管理线程的生命周期,我们只需要告诉GCD我们需要完成什么任务。GCD使用了很多的Block(闭包),所以使用起来也很方便,基本上GCD的使用是比较多的。

    任务和队列

    概念:

    任务

      任务就是操作,你要完成什么任务,就是你要完成什么操作,也就是一段代码。这段代码可以写到GCD中的Block中,所以这样添加任务特别方便。

      任务有两种执行方式:同步执行和异步执行的主要区别是会不会阻塞当前线程,知道Block中的代码执行完毕。

    如果是同步(sync)操作,它会阻塞当前线程并等待Block中的任务执行完毕,然后当前线程才能继续执行。

    如果是异步(async)操作,当前线程会继续往下执行,它不会阻塞当前线程。

    队列

      队列是用来存放任务的。队列分为两种,串行队列和并行队列。

    • 串行队列

      串行队列中的任务会根据队列的定义FIFO的执行,一个接一个的先进先出进行执行。放到串行队列中的任务,GCD会根据FIFO(先进先出)地取出来一个,执行一个,然后去下一个,执行下一个,这样一个接一个的执行。

    • 并行队列

      并行队列中的任务会根据同步和异步的不同有不同的执行方式。

    并行队列 中的任务根据同步或异步有不同的执行方式。虽然很绕,但请看下表

    blob.png

    在串行队列中执行同步任务:不会新建线程,按顺序执行任务(毫无用处)
    在串行队列中执行异步任务,会新建线程,按顺序执行任务(非常有用)

    在并行队列中执行同步任务:不会新建线程,按顺序执行任务(几乎没用)
    在并行队列中执行异步任务:会新建多个线程,但是无法确定任务的执行顺序(有用,但是很容易出错)
     

    创建队列和创建任务

     
        //GCD
        //创建队列
        //主队列,是一个特殊的串行队列,它用于刷新UI,如何需要刷新UI的工作都要在主队列中进行,所以一般耗时的任务都要放在别的线程中完成。
        dispatch_queue_t queue = dispatch_get_main_queue();
        
        //自己创建的队列:自己可以创建串行队列,也可以创建并行队列。其中第一个参数是标识符,用于DEBUG的时候标识唯一的队列,可以为空。第二个参数很重要,用来表示创建的队列是并行的还是串行的,传入DIS或者NULL表示创建了一个串行队列。传入DIS表示创建了一个并行队列。
        dispatch_queue_t queue2 = dispatch_queue_create("dl.test.QueueTest2", DISPATCH_QUEUE_SERIAL);
        
        dispatch_queue_t queue3 = dispatch_queue_create("dl.test.QueueTest3", DISPATCH_QUEUE_CONCURRENT);
        
        //创建任务
        //创建同步任务:不会另开线程(SYNC)
        dispatch_sync(queue2, ^{
            NSLog(@"%@",[NSThread currentThread]);
        });
        
        //异步任务:会另开线程(ASYNC)
        dispatch_async(queue3, ^{
            NSLog(@"%@",[NSThread currentThread]);
        });

    这里我们看两个例子,对于GCD中,同步任务的使用问题:

        NSLog(@"之前-%@", [NSThread currentThread]);
    
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@"sync - %@", [NSThread currentThread]);
        });
        
        NSLog(@"之后-%@", [NSThread currentThread]);
        
        /*
            分析:
         1.打印完第一句后,dispatch_sync 就会立即阻塞当前的主线程,然后把block中的任务放到main_queue中,可是main_queue中的任务会被取出来放到主线程中执行,但是,主线程现在已经被dispatch_sync阻塞了,所以block中的代码就不能完成,不能完成,dispatch_sync就会一直阻塞主线程,造成死锁现象,导致主线程卡死。
         */

    第二个例子

    dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
        NSLog(@"之前-%@",[NSThread currentThread]);
        dispatch_async(queue, ^{
            NSLog(@"sync之前-%@",[NSThread currentThread]);
            dispatch_sync(queue, ^{
                NSLog(@"sync-%@",[NSThread currentThread]);
            });
            NSLog(@"sync之后-%@",[NSThread currentThread]);
        });
        NSLog(@"之后-%@",[NSThread currentThread]);
        /*
            分析:
         1.首先创建一个叫做“myQueue”的串行队列。
         2.打印当前线程
         3.在myQueue的串行队列中添加异步任务(async),异步执行,不会阻塞当前线程,于是有了两条线程,一个线程继续打印“之后-%@”这句。另一个线程执行执行block中的内容,首先打印“sync之前-%@”
         4.接下来,dispatch_sync是同步任务,它会阻塞当前所在线程,一直等到sync里的任务执行完成后才会继续往下。于是 sync 就高兴的把自己 Block 中的任务放到 queue 中,可谁想 queue 是一个串行队列,一次执行一个任务,所以 sync 的 Block 必须等到前一个任务执行完毕,可万万没想到的是 queue 正在执行的任务就是被 sync 阻塞了的那个。于是又发生了死锁。
         */

    队列组

    将很多的队列添加到一个组里,当组里的所有任务都执行完成后,队列组会调用方法通知我们。

        //1.创建队列组
        dispatch_group_t group = dispatch_group_create();
        //2.创建队列
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        //3.多次使用队列组的方法执行任务,只有异步方法
        //3.1 执行3次循环
        dispatch_group_async(group, queue, ^{
            for (NSInteger i = 0; i < 3; i++) {
                NSLog(@"group-01 - %@", [NSThread currentThread]);
            }
        });
        //3.2 主队列执行8次循环
        dispatch_group_async(group, queue, ^{
            for (NSInteger i = 0; i < 8; i++) {
                NSLog(@"group-02 - %@", [NSThread currentThread]);
            }
        });
        //3.3 执行5次循环
        dispatch_group_async(group, queue, ^{
            for (NSInteger i = 0; i < 5; i++) {
                NSLog(@"group-03 - %@", [NSThread currentThread]);
            }
        });
        //4.都执行完成后自动通知
        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"完成 - %@", [NSThread currentThread]);
        });

    回到主线程

    在其他线程中操作完成后,必须回到主线程中更新UI,下边代码是回到主线程的方法:

    GCD

    //Objective-C
    dispatch_async(dispatch_get_main_queue(), ^{
    });
  • 相关阅读:
    十大经典算法总结
    十大经典算法总结
    MySQL主从同步模拟
    MySQL主从同步模拟
    高斯定理
    高斯定理
    如何修改数据决策系统登陆地址为ip
    如何修改数据决策系统登陆地址为ip
    数据库连接池问题 Max Pool Size
    数据库连接池问题 Max Pool Size
  • 原文地址:https://www.cnblogs.com/iOSDeng/p/5075941.html
Copyright © 2011-2022 走看看