面试题答案
一键面试问题
- 初始化竞争问题:在多线程环境下,多个线程可能同时判断单例对象是否已初始化,若都判断为未初始化,就会导致多次初始化单例,破坏单例的唯一性。例如,线程A和线程B同时进入了
if (singleton == nil)
判断语句块,然后两个线程都去创建单例实例。
解决方案
- 使用
dispatch_once
(适用于iOS和macOS平台):- 确保唯一性和线程安全性原理:
dispatch_once
是Grand Central Dispatch(GCD)提供的函数,它会保证代码块只被执行一次,无论有多少线程同时调用。在Swift中使用如下:
- 确保唯一性和线程安全性原理:
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
// 这里可以进行一些初始化操作
return instance
}()
private init() {}
}
- 这里`dispatch_once`的逻辑被`static let`声明的常量初始化器所隐式包含。由于`sharedInstance`是类级别的常量,它在第一次访问时被初始化,并且初始化过程是线程安全的,保证了单例的唯一性。
2. 使用@Synchronized
(在一些特定情况下可用):
- 确保唯一性和线程安全性原理:@Synchronized
关键字可以用来同步方法或代码块,使得同一时间只有一个线程能够执行被同步的代码。例如:
class Singleton {
static var sharedInstance: Singleton?
static func getInstance() -> Singleton {
@Synchronized(self) {
if sharedInstance == nil {
sharedInstance = Singleton()
}
return sharedInstance!
}
}
private init() {}
}
- 在这个例子中,`@Synchronized(self)`确保了在`getInstance`方法中的代码块在同一时间只有一个线程可以执行,从而避免了多个线程同时初始化单例的问题,保证了单例的唯一性和线程安全性。但这种方式由于引入了锁机制,在高并发场景下可能会影响性能。
3. 基于os_unfair_lock
实现(性能优化方向):
- 确保唯一性和线程安全性原理:os_unfair_lock
是一种轻量级的锁机制。在Swift中可以如下实现:
import Darwin
class Singleton {
static let sharedInstance: Singleton = {
let instance = Singleton()
return instance
}()
private static var onceToken: Int = 0
private static var lock = os_unfair_lock()
static func getInstance() -> Singleton {
if onceToken == 0 {
os_unfair_lock_lock(&lock)
defer { os_unfair_lock_unlock(&lock) }
if onceToken == 0 {
sharedInstance = Singleton()
onceToken = 1
}
}
return sharedInstance
}
private init() {}
}
- 首先通过`onceToken`进行快速判断,如果已经初始化则直接返回。当`onceToken`为0时,加锁进一步判断并初始化,这样既减少了锁的竞争,又保证了单例的唯一性和线程安全性,相比`@Synchronized`有更好的性能表现。