三种线程操作

Thread: 最轻,灵活度高,可以取消。但是只能有一个传参。
Operation: 操作对象+队列,可以取消,可以自己控制操作对象何时结束。
Grand Central Dispatch: 调度对象,操作对象, 目前没有找到取消方法。

Thread

官方文档Thread 最轻,灵活度最高

  • 方法1,使用实例方法直接创建主线程并调用执行。
  • 方法2,创建新线程,调用 start() 或 main() 方法执行线程。
  • start(), 在新建的线程中运行方法。
  • main(), 调用 routine 使方法在主线程中运行。
  • cancel(), 将线程状态置为取消状态
  • 测试代码
import UIKit

class Test {
    func start() {
        /// 方法1: 使用类方法创建线程并直接运行
        Thread.detachNewThreadSelector(#selector(startAction), toTarget: self, with: nil)
        //方式2:使用构造器方法创建线程,最后使用 main() 或者start() 启动线程使用
        let myThread = Thread(target: self,
                              selector: #selector(startAction),
                              object: nil)
        myThread.start()
        myThread.main()
    }

    //定义一个下载图片的方法,线程调用
    @objc private func startAction(){
        print("执行了线程:\(Thread.current)")
    }
}

let myClass = Test()
DispatchQueue.main.async {
    myClass.start()
}

Operation

  • Test0: 同一队列(OperationQueue)的不同操作对象(Operation)可能会在不同的线程执行;如果添加队列依赖则可以保证在统一线程中运行。
  • Test1: 可自己创建 Operation,在 main() 中写自己需要执行的代码。
  • 可以将加入队列的的对象调用方法个operation1.cancel()取消执行。
  • Objective-C 可以重载 Operation 中的方法自己控制对象何时运行结束, 关键代码如下
queue.maxConcurrentOperationCount = 1
self.willChangeValue(for: \ActionOperation.isFinished)
self.willfinish = true
self.didChangeValue(for: \ActionOperation.isFinished)
  • 测试代码
import UIKit

class Test0 {
    func start() {
        let operation0 = BlockOperation(block: {
            print("队列-0, 执行了, \(Thread.current)")
        })
        let operation1 = BlockOperation(block: {
            print("队列-1, 执行了, \(Thread.current)")
        })

        //创建一个NSOperationQueue实例并添加operation
        let queue = OperationQueue()
        print("准备运行队列-0")
        queue.addOperation(operation0)
        print("准备运行队列-1")
        queue.addOperation(operation1)
//        operation1.cancel()
    }
}

class Test1 {
    func start() {
        /// 创建线程对象
        let actionOperation = ActionOperation()

        let nextOperation = BlockOperation {
            print("finish!!!")
        }
        let queue = OperationQueue()
        queue.maxConcurrentOperationCount = 1
        queue.addOperation(actionOperation)
        queue.addOperation(nextOperation)
    }
}

class ActionOperation: Operation {
    private var willfinish: Bool = false

    override func main(){
        print("对象执行了\(Thread.current)")

        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
            print("我真的执行结束了")
            self.willChangeValue(for: \ActionOperation.isFinished)
            self.willfinish = true
            self.didChangeValue(for: \ActionOperation.isFinished)
        }
        print("只是方法完毕!!!")
    }

    override var isFinished: Bool {
        print("----\(ffffinish)")
        return ffffinish
    }
}

let test0 = Test0()
DispatchQueue.main.async {
    test0.start()
}

let test1 = Test1()

DispatchQueue.main.async {
    test1.start()
}

GCD Group

let queue = DispatchQueue(label: "current", qos: DispatchQoS.userInteractive, attributes: .concurrent)
        let gcdGroup = DispatchGroup()
        gcdGroup.enter()
        queue.async {
            print("first")
            DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
                print("first_after")
                gcdGroup.leave()
            }
        }
        gcdGroup.enter()
        queue.async {
            print("second")
            DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
                print("second_after")
                gcdGroup.leave()
            }
        }
        gcdGroup.notify(queue: queue) {
            print("finish")
        }
//second
//first
//second_after
//first_after
//finish

Grand Central Dispatch

GCD 获取各种队列的方法

创建串行队列
let serial = DispatchQueue(label: "serialQueue1")

//创建并行队列
let concurrent = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)

//获取全局队列
let globalQueue = DispatchQueue.global(qos: .default)

//获取主线程队列
let mainQueue = DispatchQueue.main
  • 全局队列
  • DispatchQueue.global…sync { Code } 同步当前线程执行代码块, Code 代码块中的代码执行完毕后,才会继续执行下面方法, 不会造成亨死锁。
  • DispatchQueue.global…async 重新开启线程,执行代码块。
//async异步追加Block块(async函数不做任何等待)
DispatchQueue.global(qos: .default).async {
    //处理耗时操作的代码块...
    print("do work: \(Thread.current)")

    //操作完成,调用主线程来刷新界面
    DispatchQueue.main.async {
        print("main refresh: \(Thread.current)")
    }
}

//添加同步代码块到global队列
//不会造成死锁,但会一直等待代码块执行完毕
print("当前的线程:\(Thread.current)")
serial.async {
    DispatchQueue.global(qos: .default).sync {
        print("sync1: \(Thread.current)")
        sleep(3)
    }
    print("end")
}
  • 一下代码慎用,如果执行环境为主线程,会造成死锁。
DispatchQueue.main.sync {
    print("sync2")
}

GCD 操作对象

  • 串行异步、同步队列保证在同一线程中顺序执行。
  • DispatchWorkItemopen 类,不能继承创建子类
let workItem0 = DispatchWorkItem {
    print("workItem0::\(Thread.current)")
}

let workItem1 = DispatchWorkItem {
    print("workItem1::\(Thread.current)")
}
创建串行队列
let serial = DispatchQueue(label: "serialQueue1")
serial.async(execute: workItem0)
serial.async(execute: workItem1)
//serial.sync(execute: workItem0)
//serial.sync(execute: workItem1)
  • 并行同步队列,保证在同一线程中运行,运行顺序确定。
  • 并行异步队列,不能保证在同一线程中运行,运行顺序不确定。
let workItem0 = DispatchWorkItem {
    print("workItem0::\(Thread.current)")
    sleep(0)
}

let workItem1 = DispatchWorkItem {
    print("workItem1::\(Thread.current)")
}
//创建并行队列
let concurrent = DispatchQueue(label: "concurrentQueue1", attributes: .concurrent)
DispatchQueue.global().async {
    concurrent.async(execute: workItem0)
	concurrent.async(execute: workItem1)
	//concurrent.sync(execute: workItem0)
	//concurrent.sync(execute: workItem1)
}