多线程

作者: 红色海_ | 来源:发表于2019-10-16 16:16 被阅读0次

    https://blog.csdn.net/PeaksLee/article/details/78270157

    • NSThread
    • GCD
    • NSOperation & NSOperationQueue
    1. NSThread

    苹果封装, 完全面向对象。但生命周期需要手动管理.

    --------------------------------------
    ////先创建再启动//////////////////////
    --------------------------------------
    OBJECTIVE-C
      // 创建
      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()
    --------------------------------------
    ////创建并自动启动//////////////////////////
    --------------------------------------
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
    
    NSThread.detachNewThreadSelector("run:", toTarget: self, withObject: nil)
    --------------------------------------
    ////使用 NSObject 的方法创建并自动启动////////////
    --------------------------------------
    @interface NSObject (NSThreadPerformAdditions)
    - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;
    - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
        // equivalent to the first method with kCFRunLoopCommonModes
    
    - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
    - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
        // equivalent to the first method with kCFRunLoopCommonModes
    - (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
    
    @end
    ///////////////////////////////////////////////////
    OBJECTIVE-C
     [self performSelectorInBackground:@selector(run:) withObject:nil];
    
    SWIFT
    苹果认为 performSelector: 不安全所以在Swift 去掉了这个方法。
    
    其他方法.............不一一列举了。。
    @property (readonly, getter=isExecuting) BOOL executing;
    @property (readonly, getter=isFinished) BOOL finished;
    @property (readonly, getter=isCancelled) BOOL cancelled;
    
    2. GCD

    苹果为多核的并行提出的解决方案,
    合理地利用更多的CPU内核(比如双核、四核),
    自动管理线程的生命周期(创建线程、调度任务、销毁线程),
    使用的是 c语言,利用了 Block(Swift里叫做闭包),
    使用起来更加方便灵活。

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

    即操作 你想要干什么,就是一段代码,在 GCD 中就是一个 Block,所以添加任务十分方便。

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

    区别:
    是否会创建新的线程。
    会不会阻塞当前线程,直到 Block 中的任务执行完毕!

    同步(sync) 操作,会阻塞当前线程并等待 Block 中的任务执行完毕,然后当前线程才会继续往下运行。
    异步(async)操作,当前线程会直接往下执行,不会阻塞当前线程。

    队列:用于存放任务。 串行队列 并行队列。

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

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

    创建队列
    主队列:这是一个特殊的 串行队列。它用于刷新 UI,

    任何需要刷新 UI 的工作都要在主队列执行,
    一般耗时的任务都要放到别的线程执行。

      //OBJECTIVE-C
      dispatch_queue_t queue = ispatch_get_main_queue();
      //SWIFT
      let queue = ispatch_get_main_queue()
    
    自己创建的队列: 串行 并行

    它有两个参数,第一个参数是标识符,用于 DEBUG 的时候标识唯一的队列,可以为空。第二个才是最重要的。
    第二个参数用来表示创建的队列是串行的还是并行的,
    DISPATCH_QUEUE_SERIAL 或 NULL 创建串行队列。
    DISPATCH_QUEUE_CONCURRENT 创建并行队列。

    //OBJECTIVE-C
      //串行队列
      dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", NULL);
      dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);
      //并行队列
      dispatch_queue_t queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);
     
      //SWIFT
      //串行队列
      let queue = dispatch_queue_create("tk.bourne.testQueue", nil);
      let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL)
      //并行队列
      let queue = dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT)
    
    全局并行队列:

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

    //OBJECTIVE-C
      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)
    
    创建任务

    同步任务: 阻塞当前线程 (SYNC)

    OBJECTIVE-C
      dispatch_sync(<#queue#>, ^{
          //code here
          NSLog(@"%@", [NSThread currentThread]);
      });
    SWIFT
      dispatch_sync(<#queue#>, { () -> Void in
          //code here
          println(NSThread.currentThread())
    
    异步任务:不会阻塞当前线程 (ASYNC)
    OBJECTIVE-C
    
      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 就会一直阻塞主线程,这就是死锁现象。导致主线程一直卡死。

    示例二:
    以下代码会产生什么结果?

    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())
    

    未完 待续。。。

    相关文章

      网友评论

          本文标题:多线程

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