前言:下面出现的练习 code 在 SwiftyThreadExercise
一些基本概念
- 进程:在系统中运行的一个应用程序,每个进程间是独立的。每个进程均运行在其专有的且受保护的内存空间中。
- 线程:一个进程「程序」的所有任务都是在线程中执行的,每个进程至少有一个线程「主线程」。
- 主线程:一个 iOS 程序运行后,会默认开启一条线程,称之为“主线程” 或 “UI 线程”。主线程用来处理 UI 事件(如:点击,滚动,拖拽等事件),也是用来显示/刷新 UI 界面。
- 多线程:一个进程可以开启多条线程,多条线程可以并行「同时」执行不同的任务,多线程并发「同时」执行,其实就是 CPU 快速的在多条线程间调度「切换」。
- 同步:在当前线程,按照先后顺序执行,不开启新的线程。
- 异步:在当前线程,开启一个或多个线程,可不按照顺序执行。
- 队列:承载线程任务的一个容器。
- 并发:线程可以同时一起执行。
- 串行:线程执行顺序,只能按照先后顺序,依次执行。
iOS 中线程实现方案
pthread
: 跨平台/可移植;线程生命周期需要人为管理。 Note: 暂不讨论, 理由:几乎用不到NSThread
: 使用面向对象;相比 pthread
更加直观操作线程对象;线程生命周期需要人为管理。CCD
: Grand Central Dispatch, 充分利用多核,允许多任务在队列总串行或并行的执行。自动线程的生命周期。旨在替代 NSThread。NSOperation
: 基于 CGD
,比 GCD 多了一些实用功能;更加面向对象;线程生命周期需要人为管理。
NSThread
NSThread 有以下几种状态:
- 新建「创建」:进入就绪状态 -> 运行状态。 当线程任务执行完毕,自动进入死亡状态。
- 就绪状态 runnable。
- 强制停止线程,cancel。
- 运行,running。
- 阻塞状态。
- 死亡状态。exit, 一旦线程停止「死亡」,就不能再次开启任务了。
let thread1 = Thread(target: self, selector: #selector(onThreadRun), object: nil) thread1.start()
Thread.detachNewThreadSelector(#selector(onThreadRun), toTarget: self, with: nil)
Thread.detachNewThread { }
self.performSelector(inBackground: #selector(onThreadRun), with: nil)
self.performSelector(onMainThread: #selector(onThreadRun), with: nil, waitUntilDone: false)
self.perform(#selector(onThreadRun), on: thread, with: nil, waitUntilDone: true)
let currentThread = Thread.current
let mainThread= Thread.main
let isMainThread = Thread.isMainThread
Thread.current.isExecuting
Thread.exit()
|
GCD
GCD 全称 Grand Central Dispatch, 其有如下优势:
- 多核并行运算的解决方案
- 自动利用更多的 CPU 内核(如双核、四核)
- 自动管理线程的生命周期
- 程序员只需要告诉 GCD 想要执行什么任务,不需要编写任何线程管理代码

任务 & 队列
特有队列
DispatchQueue.main.async { }
DispatchQueue.main.sync { }
DispatchQueue.global().async { }
DispatchQueue.global().sync { }
|
串行队列
let queue = DispatchQueue(label: "ai.studio.david.queue.1")
print("queue execute before, current thread = \(Thread.current)")
queue.sync { (0...5).forEach { print("index = \($0), current thread = \(Thread.current)") } }
queue.sync { (0...5).forEach { print("index = \($0), current thread = \(Thread.current)") } }
print("queue execute after, current thread = \(Thread.current)")
let queue = DispatchQueue(label: "ai.studio.david.queue.1")
print("queue execute before, current thread = \(Thread.current)")
queue.async { (0...5).forEach { print("queue 1, index = \($0), current thread = \(Thread.current)") } }
queue.async { (0...5).forEach { print("queue 2,index = \($0), current thread = \(Thread.current)") } }
print("queue execute after, current thread = \(Thread.current)")
|
并发队列
let queue = DispatchQueue(label: defaultQueueLabel, attributes: .concurrent)
print("queue execute before, current thread = \(Thread.current)")
queue.sync { (0...5).forEach { print("queue 1, index = \($0), current thread = \(Thread.current)") } }
print("queue execute middle, current thread = \(Thread.current)")
queue.sync { (0...5).forEach { print("queue 2,index = \($0), current thread = \(Thread.current)") } }
print("queue execute after, current thread = \(Thread.current)")
let queue = DispatchQueue(label: defaultQueueLabel, attributes: .concurrent) print("queue execute before, current thread = \(Thread.current)") (0..<1000).forEach { print("index = \($0), current thread = \(Thread.current)") }
queue.async { print("task1, current thread = \(Thread.current)") } queue.async { print("task2, current thread = \(Thread.current)") } queue.async { print("task3, current thread = \(Thread.current)") } queue.async { print("task4, current thread = \(Thread.current)") } queue.async { print("task5, current thread = \(Thread.current)") }
print("queue execute after, current thread = \(Thread.current)")
|
其他方法
self.perform(#selector(onDelayHandler), with: nil, afterDelay: 2)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { }
DispatchQueue.global().asyncAfter(deadline: .now() + 2) { }
Timer.scheduledTimer(timeInterval: 2, target: self, selector: #selector(onDelayHandler), userInfo: nil, repeats: false)
DispatchQueue.concurrentPerform(iterations: 10) { index in }
|
NSOperation & NSOperationQueue
- NSOperation & NSOperationQueue 是苹果对 GCD 的封装
- NSOperation & NSOperationQueue 分别相当于 GCD 的任务和队列
- NSOperation 是一个抽象类,可以使用其子类
BlockOperation
, 当然也可以自定义子类 - NSOperationQueue 支持
暂停
、恢复
、取消
操作。这些操作,都是对后面未执行的任务进行操作,不会影响当前正在进行的任务,且 取消
不可以恢复。
NSOperation 实现多线程步骤
- 创建操作:先将需要执行的操作封装到一个 NSOperation 对象中。
- 创建队列:创建 NSOperationQueue 对象。
- 将操作加入到队列中:将 NSOperation 对象添加到NSOperationQueue 对象中。
- 之后,系统就会自动将 NSOperationQueue 中的 NSOperation 取出来,在新线程中执行操作。
BlockOperation 的使用
let blockOperation = BlockOperation { print("operation1, block1, current thread = \(Thread.current)") }
blockOperation.start()
let blockOperation = BlockOperation { print("operation1, block1, current thread = \(Thread.current)") }
blockOperation.addExecutionBlock { print("operation1, block2, current thread = \(Thread.current)") }
blockOperation.addExecutionBlock { print("operation1, block3, current thread = \(Thread.current)") }
blockOperation.start()
|
NSOperation 自定义子类
可以通过实现 main 方法来自定义实现一个 NSOperation 的子类。
class CustomOperation: Operation { override func main() { var isRunning = true var autoincrement: Int = 0 while isRunning { if isCancelled { isRunning = false break } if autoincrement >= 100 { isRunning = false break } print("current value = \(autoincrement), current thread = \(Thread.current)") autoincrement += 1 } } }
|
NSOperationQueue
NSOperationQueue 有两种队列形式:主队列 & 自定义队列
- 主队列:凡是添加到主队列中的操作,都会放到主线程中执行
- 自定义队列:操作自动放到子线程中执行,同时包含了:串行、并发功能。
let mainQueue = OperationQueue.main
let customQueue = OperationQueue()
|
添加任务到队列中
let operationQueue = OperationQueue()
operationQueue.maxConcurrentOperationCount = OperationQueue.defaultMaxConcurrentOperationCount
let blockOperation = BlockOperation { print("operation1, block1, current thread = \(Thread.current)") }
operationQueue.addOperation(blockOperation)
blockOperation.addDependency(blockOperation2) operationQueue.addOperation(blockOperation) operationQueue.addOperation(blockOperation2)
|
Author: David硕
Permalink: http://davidxiaoshuo.github.io/iOS/thread_summary_1/
License: Copyright (c) 2019 CC-BY-NC-4.0 LICENSE
Slogan: Write readable code!