zoukankan      html  css  js  c++  java
  • iOS多线程NSThread和GCD

    在iOS中啊  其实有多种方法实现多线程 这里只记录两个比较常用的  或者说我比较常用的

    一个就是BSThread 另一个就是一听名字就比较霸气的妇孺皆知的GCD

    先说一下NSThread吧 这个方式一般情况下不推荐使用  因为我也不是经常使用这个  因为这个比较麻烦 需要我们自己来创建管理和销毁

    看一下代码

    (oc的)

     // 创建
      NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];

      // 启动
      [thread start];

    (swift的)

     //创建
      let thread = NSThread(target: self, selector: "run:", object: nil)

      //启动
      thread.start()

    代码就不需要解释了吧

    下面开始霸气的GCD

    Grand Central Dispatch,听名字就霸气。它是苹果为多核的并行运算提出的解决方案,所以会自动合理地利用更多的CPU内核(比如双核、四核),最重要的是它会自动管理线程的生命周期(创建线程、调度任务、销毁线程),完全不需要我们管理,我们只需要告诉干什么就行。同时它使用的也是 c语言,不过由于使用了 Block(Swift里叫做闭包),使得使用起来更加方便,而且灵活。所以基本上大家都使用 GCD 这套方案,老少咸宜,实在是居家旅行、杀人灭口,必备良药。

    GCD 中,加入了两个非常重要的概念: 任务队列

    任务有两种执行方式: 同步执行异步执行

    同步(sync) 和 异步(async) 的主要区别在于会不会阻塞当前线程,直到 Block 中的任务执行完毕!如果是 同步(sync) 操作,它会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。如果是 异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。

    队列:用于存放任务。一共有两种队列, 串行队列并行队列

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

    放到并行队列的任务,GCD 也会 FIFO的取出来,但不同的是,它取出来一个就会放到别的线程,然后再取出来一个又放到另一个的线程。这样由于取的动作很快,忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD 会根据系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。

    主队列都已经很熟悉了吧 就不用解释了吧 一般刷新UI

    创建主队列

    (oc)

    dispatch_queue_t queue = dispatch_get_main_queue();
    (swift)

    let queue = ispatch_get_main_queue()

    自己创建队列

    (oc)

    //串行队列(第一个参数是标识,用来标识线程,参数2传NULL或DISPATCH_QUEUE_SERIAL代表串行队列,传DISPATCH_QUEUE_CONCURRENT代表并行队列)
      dispatch_queue_t queue = dispatch_queue_create("lwk", NULL);
      dispatch_queue_t queue = dispatch_queue_create("lwk", DISPATCH_QUEUE_SERIAL);
      //并行队列
      dispatch_queue_t queue = dispatch_queue_create("lwk", DISPATCH_QUEUE_CONCURRENT);

    (swift)

    let queue = dispatch_queue_create("lwk", nil);
      let queue = dispatch_queue_create("lwk", DISPATCH_QUEUE_SERIAL)
      //并行队列
      let queue = dispatch_queue_create("lwk", DISPATCH_QUEUE_CONCURRENT)

    全局并行队列  只要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。

    (oc)

     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    (swift)

    let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

    创建任务

    同步任务会阻塞当前线程

    (oc)

    dispatch_sync(<#queue#>, ^{
          //code here
          NSLog(@"%@", [NSThread currentThread]);
      });

    (swift)

     dispatch_sync(<#queue#>, { () -> Void in
          //code here
          println(NSThread.currentThread())
      })

    异步任务不会阻塞当前线程

    (oc)

     dispatch_async(<#queue#>, ^{
          //code here
          NSLog(@"%@", [NSThread currentThread]);
      });

    (swift)

     dispatch_async(<#queue#>, { () -> Void in
          //code here
          println(NSThread.currentThread())
      })

    看一下网上的示例

    NSLog("之前 - %@", NSThread.currentThread())
    dispatch_sync(dispatch_get_main_queue(), { () -> Void in
            NSLog("sync - %@", NSThread.currentThread())
    })
    NSLog("之后 - %@", NSThread.currentThread())

    看一下上面的运行结果

    只会打印第一句:之前 - <NSThread: 0x7fb3a9e16470>{number = 1, name = main} ,然后主线程就卡死了

    解释:同步任务会阻塞当前线程,然后把 Block 中的任务放到指定的队列中执行,只有等到 Block 中的任务完成后才会让当前线程继续往下运行。那么这里的步骤就是:打印完第一句后,dispatch_sync 立即阻塞当前的主线程,然后把 Block 中的任务放到 main_queue 中,可是 main_queue 中的任务会被取出来放到主线程中执行,但主线程这个时候已经被阻塞了,所以 Block 中的任务就不能完成,它不完成,dispatch_sync 就会一直阻塞主线程,这就是死锁现象。导致主线程一直卡死。

    示例2

    let queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL)

       NSLog("之前 - %@", NSThread.currentThread())

        dispatch_async(queue, { () -> Void in
            NSLog("sync之前 - %@", NSThread.currentThread())
            dispatch_sync(queue, { () -> Void in
                 NSLog("sync - %@", NSThread.currentThread())
            })
            NSLog("sync之后 - %@", NSThread.currentThread())
       })

      NSLog("之后 - %@", NSThread.currentThread())

    很明显 sync - %@sync之后 - %@ 没有被打印出来!

    分析:我们按执行顺序一步步来哦:

    使用 DISPATCH_QUEUE_SERIAL 这个参数,创建了一个 串行队列。 打印出 之前 - %@ 这句。

    dispatch_async 异步执行,所以当前线程不会被阻塞,于是有了两条线程,一条当前线程继续往下打印出 之后 - %@这句, 另一台执行 Block 中的内容打印 sync之前 - %@ 这句。因为这两条是并行的,所以打印的先后顺序无所谓。 注意,高潮来了。现在的情况和上一个例子一样了。dispatch_sync同步执行,于是它所在的线程会被阻塞,一直等到 sync 里的任务执行完才会继续往下。于是 sync 就高兴的把自己 Block 中的任务放到 queue 中,可谁想 queue 是一个串行队列,一次执行一个任务,所以 sync 的 Block 必须等到前一个任务执行完毕,可万万没想到的是 queue 正在执行的任务就是被 sync 阻塞了的那个。于是又发生了死锁。所以 sync 所在的线程被卡死了。剩下的两句代码自然不会打印。

    队列组

    队列组可以将很多队列添加到一个组里,这样做的好处是,当这个组里所有的任务都执行完了,队列组会通过一个方法通知我们。下面是使用方法,这是一个很实用的功能。

    (oc)

    //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, dispatch_get_main_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]);

    (swift)

    //1.创建队列组
    let group = dispatch_group_create()
    //2.创建队列
    let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

    //3.多次使用队列组的方法执行任务, 只有异步方法
    //3.1.执行3次循环
    dispatch_group_async(group, queue) { () -> Void in
        for _ in 0..<3 {
            NSLog("group-01 - %@", NSThread.currentThread())
        }
    }

    //3.2.主队列执行8次循环
    dispatch_group_async(group, dispatch_get_main_queue()) { () -> Void in
        for _ in 0..<8 {
            NSLog("group-02 - %@", NSThread.currentThread())
        }
    }

    //3.3.执行5次循环
    dispatch_group_async(group, queue) { () -> Void in
        for _ in 0..<5 {
            NSLog("group-03 - %@", NSThread.currentThread())
        }
    }

    //4.都完成后会自动通知 dispatch_group_notify(group, dispatch_get_main_queue()) { () -> Void in
        NSLog("完成 - %@", NSThread.currentThread())
    }

    我觉得上面的东西你都摸索完事后就可以自己任意的想怎么开线程就怎么开线程了  想在哪开就在哪开  就是这么任性了 哈哈哈哈  不过劝你也不要乱开线程  容易走火  哈哈哈哈

    完事 此致

  • 相关阅读:
    Unity 状态机切换
    Unity3d 血条脚本
    最简单的Python群聊
    EFCore 多字段排序分页法
    搭建react+redux+vscode+typescript开发环境
    C# 4格A*自动寻径
    Sql删除表中多余的重复记录
    ABP弹出提醒用户的错误信息
    百度地图 驾车路线编辑粗浅实例
    .NetCore3.1 WebApi中Swagger配置
  • 原文地址:https://www.cnblogs.com/lwk151124/p/5733591.html
Copyright © 2011-2022 走看看