首页 > 技术文章 > iOS多线程主题

quanxi 2016-12-31 21:53 原文

下面是:2个并发进程、和2个并发线程的示意图:

下面介绍三种多线程技术(Thread、Cocoa Operation、Grand Central Dispatch):

1、最轻量级Thread(需要自己管理线程的生命周期和同步,所以不常用):线程同步对数据的加锁会导致一定的系统开销。但偶尔也会有一定的用处,如Thread.current可以获得当前线程,这种使用就很方便。

//下面是创建Thread的两种方法
//方法一:使用类方法,创建线程(创建好,就启动了)
Thread.detachNewThreadSelector(#selector(addOne), toTarget: self, with: nil)
//方法二:线程实例化,采用便利构造器
let thread2 = Thread(target: self, selector: #selector(addTwo), object: nil)
thread2.start()

2、Cocoa Operation(相关类Operation和OperationQueue):这种方法就不需要关心线程管理和数据同步,只需把重点放在多线程分别要执行的任务。

其中Operation是个抽象类,使用它必须用它的子类,可以自定义,也可以用BlockOperation类。要让Operation子类的对象,执行它的任务(方法),就需要把这个对象,add进入OperationQueue对象的操作队列,依次执行:
let blockOne = BlockOperation(block: addOne)
let blockTwo = BlockOperation(block: addTwo)
let queue = OperationQueue()
queue.addOperation(blockOne)
queue.addOperation(blockTwo)

3、Grand Central Dispatch(GCD):

GCD会自动合理地利用更多的CPU内核(即根据系统负载来自动增减线程数量,从而减少了上下文切换,而增加计算效率)、自动管理线程的生命周期(如创建线程、调度任务、自动同步,无需加锁、销毁线程等,使用就不用过多关心这些与处理事物无关的代码),所以方便的GCD是我们学习iOS多线程的重点。
使用GCD就是使用dispatch queue(调度队列)的对象,用来接受任务并执行,而且与以上两种方法不同的是,dispatch queue是可以并发的,也可以FIFO串行。

GCD有两种队列(串行、并行,一个队列对象就代表一个线程),用于存放任务,任务的执行也有两种同步、异步执行。具体如何执行,理解下图:

 创建队列

主队列:主线程中的唯一队列,用于刷新UI(因为主线程主队列是唯一的,所以这种操作也是串行的),所以其他的耗时任务要放到其他线程的队列中执行。获得主队列:let mainQueue = DispatchQueue.main

自定义队列:

对于并行队列,有4个常用的执行优先级(由高到低):.userInitiated—>.default—>.utility—>.background,一般最后一个就用于执行不太关心、极其费时的后台任务

  • 创建串行队列:let serial = DispatchQueue(label: "serialQueue"),一个串行队列之中,任务是FIFO的,但是可以创建多个串行队列,而串行队列之间是并发的。
  • 创建并行队列(对于并发任务,一般就用系统提供的全局并行队列):let conflict = DispatchQueue(label: "conflictQueue", qos: .default, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
  • 全局并行队列:let globalQueue = DispatchQueue.global(qos: .default),qos就是优先级。

然后就是创建任务了:

同步任务:在任务执行时,线程的队列会等待执行完成后,才执行下一个任务,但是却可以追加新的任务(虽然没有立即执行:阻塞)

        let globalQueue = DispatchQueue.global(qos: .default)
        globalQueue.sync {
            addOne()
        }

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

        let globalQueue = DispatchQueue.global(qos: .default)
        globalQueue.async {
            self.addOne()
        }
        let mainQueue = DispatchQueue.main
        mainQueue.async {
            self.addTwo()   //主线程先执行
        }

 

推荐阅读