
1) 【一句话结论】在iOS多线程中处理数据共享时,需通过同步机制(如锁、原子操作)保证线程安全,避免竞争条件,具体选择取决于场景(如互斥访问 vs 等待通知)。
2) 【原理/概念讲解】多线程下多个线程可能同时访问共享数据,若不处理会导致数据不一致(竞争条件)。锁(如NSLock)通过互斥机制,确保同一时间只有一个线程能执行受保护的代码块;原子操作(如Atomic)则是编译器或硬件层面保证的不可分割操作,适用于基本数据类型(如int、float)。类比:锁就像会议室的钥匙,只有一把钥匙,同一时间只能一个人进;原子操作就像瞬间完成的书写动作,中间不会被中断。
3) 【对比与适用场景】
| 工具 | 定义 | 特性 | 使用场景 | 注意点 |
|---|---|---|---|---|
| NSLock | 线程互斥锁 | 互斥访问,阻塞等待 | 互斥执行代码块(如更新共享变量) | 需手动释放,避免死锁 |
| DispatchSemaphore | 信号量(计数型) | 控制并发线程数量,可等待 | 等待多个任务完成(如下载多个文件) | 初始值设为0时,线程会阻塞等待释放 |
| Atomic(类型) | 基本数据类型的原子操作 | 编译器/硬件保证不可分割 | 基本类型变量(如计数器、标志位) | 仅适用于基本类型,复杂对象需封装 |
4) 【示例】
假设有一个共享的计数器,多个线程同时递增。用NSLock保护:
var sharedCounter = 0
let lock = NSLock()
func incrementCounter() {
lock.lock()
sharedCounter += 1
lock.unlock()
}
或用DispatchSemaphore:
var semaphore = DispatchSemaphore(value: 1)
var sharedCounter = 0
func incrementCounter() {
semaphore.wait()
sharedCounter += 1
semaphore.signal()
}
原子操作示例(Swift中基本类型支持):
var atomicCounter: Atomic<Int> = 0
func incrementAtomic() {
atomicCounter += 1
}
5) 【面试口播版答案】(约90秒)
“在iOS多线程中处理数据共享时,核心是通过同步机制保证线程安全,避免竞争条件。具体来说,当需要互斥访问共享数据(比如更新一个全局计数器)时,会使用NSLock,通过锁的互斥特性确保同一时间只有一个线程能执行受保护的代码块,避免数据不一致。比如在多个线程同时递增一个共享计数器时,用NSLock包裹更新逻辑,锁住后执行加1,解锁后其他线程才能继续。另外,对于需要控制并发线程数量的场景,比如下载多个文件,会使用DispatchSemaphore,初始值设为0,线程执行时先等待信号量,完成后再释放,这样能控制同时运行的线程数。而原子操作(如Atomic)则适用于基本数据类型,比如Swift中的Atomic<Int>,编译器会保证加1操作是不可分割的,适用于简单的计数器或标志位,不需要手动加锁。总结来说,选择哪种方式取决于具体需求:互斥访问用锁,控制并发用信号量,基本类型操作用原子操作。”
6) 【追问清单】
7) 【常见坑/雷区】