MST

星途 面试题库

面试题:Objective-C中如何通过锁机制实现线程安全的单例模式

请使用Objective-C代码实现一个线程安全的单例模式,要求清晰说明锁机制在其中的应用原理和作用,以及不同锁机制对单例实现的性能影响。
45.8万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试

线程安全的单例模式实现

在Objective-C中,实现线程安全的单例模式可以使用GCD(Grand Central Dispatch)的dispatch_once函数。以下是示例代码:

#import <Foundation/Foundation.h>

@interface Singleton : NSObject

@property (nonatomic, strong, readonly) NSString *sharedValue;

+ (instancetype)sharedInstance;

@end

@implementation Singleton

static Singleton *sharedSingleton = nil;

+ (instancetype)sharedInstance {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedSingleton = [[self alloc] init];
        sharedSingleton.sharedValue = @"Initial value";
    });
    return sharedSingleton;
}

@end

锁机制的应用原理和作用

  1. 原理dispatch_once函数内部使用了一种高效的原子操作来确保代码块只被执行一次。它通过一个dispatch_once_t类型的变量(在上述代码中是onceToken)来跟踪代码块是否已经执行过。当第一次调用dispatch_once时,它会执行传入的代码块,并将onceToken标记为已执行。后续调用dispatch_once时,只要onceToken已标记,就不会再次执行代码块。
  2. 作用:这种机制确保了单例对象在多线程环境下的唯一性。无论有多少个线程同时调用sharedInstance方法,单例对象只会被创建一次,避免了多个线程同时创建单例对象的竞争条件,从而保证了线程安全。

不同锁机制对单例实现的性能影响

  1. 互斥锁(Mutex):如果不使用dispatch_once,而使用互斥锁来实现单例,每次调用获取单例的方法时都需要加锁和解锁操作。虽然可以保证线程安全,但加锁和解锁操作是有开销的,特别是在高并发环境下,频繁的加锁解锁会严重影响性能。例如:
#import <Foundation/Foundation.h>
#import <pthread.h>

@interface Singleton : NSObject

@property (nonatomic, strong, readonly) NSString *sharedValue;

+ (instancetype)sharedInstance;

@end

@implementation Singleton

static Singleton *sharedSingleton = nil;
static pthread_mutex_t mutex;

+ (void)initialize {
    pthread_mutex_init(&mutex, NULL);
}

+ (instancetype)sharedInstance {
    pthread_mutex_lock(&mutex);
    if (!sharedSingleton) {
        sharedSingleton = [[self alloc] init];
        sharedSingleton.sharedValue = @"Initial value";
    }
    pthread_mutex_unlock(&mutex);
    return sharedSingleton;
}

+ (void)dealloc {
    pthread_mutex_destroy(&mutex);
}

@end
  1. 自旋锁(Spin Lock):自旋锁在等待锁时不会使线程进入睡眠状态,而是在原地不断尝试获取锁。对于单例模式,如果获取单例的操作非常频繁且锁的持有时间很短,自旋锁可能会有较好的性能,因为避免了线程上下文切换的开销。但如果锁的持有时间较长,自旋锁会浪费CPU资源,导致性能下降。
  2. dispatch_oncedispatch_once使用的机制比普通的锁更高效。它在第一次执行代码块后,后续调用几乎没有额外开销,因为不需要每次都进行加锁解锁操作。在单例模式下,由于单例对象通常只创建一次,dispatch_once能很好地满足需求,同时保持高性能。

综上所述,dispatch_once是实现Objective-C线程安全单例模式的推荐方式,因为它既保证了线程安全,又具有良好的性能。