MST

星途 面试题库

面试题:Objective-C懒加载模式下的线程安全问题及解决方案

在多线程环境下,Objective-C的懒加载模式可能会出现哪些线程安全问题?请举例说明,并阐述至少两种解决这些问题的常用方法及其优缺点。
17.3万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

线程安全问题及举例

在多线程环境下,Objective-C 的懒加载模式可能出现以下线程安全问题:

  1. 多次初始化:多个线程同时判断属性为 nil,进而都尝试进行初始化,导致属性被多次初始化。例如,假设有一个单例类使用懒加载模式创建单例实例:
@interface Singleton : NSObject
@property (nonatomic, strong) static Singleton *sharedInstance;
+ (instancetype)sharedInstance;
@end

@implementation Singleton
+ (instancetype)sharedInstance {
    if (!_sharedInstance) {
        _sharedInstance = [[self alloc] init];
    }
    return _sharedInstance;
}
@end

在多线程环境下,可能会有多个线程同时进入 if (!_sharedInstance) 判断,都认为 _sharedInstancenil,从而创建多个实例。

解决方法及其优缺点

  1. 使用 @synchronized 关键字
    • 实现方式
+ (instancetype)sharedInstance {
    @synchronized(self) {
        if (!_sharedInstance) {
            _sharedInstance = [[self alloc] init];
        }
    }
    return _sharedInstance;
}
- **优点**:实现简单,只需在关键代码块添加 `@synchronized` 即可。
- **缺点**:性能较低,因为 `@synchronized` 使用的是互斥锁,会阻塞其他线程,影响多线程并发性能。特别是在频繁调用懒加载的情况下,性能瓶颈会比较明显。

2. 使用 dispatch_once - 实现方式

+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}
- **优点**:性能高,`dispatch_once` 只执行一次初始化代码,并且采用了高效的实现机制,不会对其他线程造成阻塞。它在底层使用了原子操作和内存屏障,保证了线程安全和初始化的唯一性。
- **缺点**:只能用于初始化一次的场景,如果需要动态重新初始化属性,`dispatch_once` 就不适用了。而且对于非单例的懒加载属性,使用 `dispatch_once` 需要一些额外的设计来管理 `dispatch_once_t` 变量的作用域。