从实例到单例:Objective-C 单例类的线程安全实现方案

从实例到单例:Objective-C 单例类的线程安全实现方案

在 Objective-C 中实现线程安全的单例模式需解决两个核心问题:

  1. 确保全局唯一实例
  2. 防止多线程环境下的竞态条件
一、基础实现方案
objectivec 复制代码
// MySingleton.h
@interface MySingleton : NSObject
+ (instancetype)sharedInstance;
@end

// MySingleton.m
@implementation MySingleton
+ (instancetype)sharedInstance {
    static MySingleton *_sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedInstance = [[self alloc] init];
    });
    return _sharedInstance;
}
@end

关键组件

  • static 变量保证实例生命周期与程序相同
  • dispatch_once_t 确保代码块仅执行一次
  • GCD 的 dispatch_once 提供原子性操作
二、线程安全分析

T_1, T_2 为并发线程,其执行过程满足: $$P(T_1 \cap T_2) = \emptyset \implies \text{单例唯一性}$$ dispatch_once 的底层实现基于:

  1. 原子性内存屏障
  2. 信号量锁机制
  3. 双重检查锁定模式
三、防御性改进方案

防止通过其他方式创建实例:

objectivec 复制代码
// 重写 allocWithZone 方法
+ (instancetype)allocWithZone:(struct _NSZone *)zone {
    return [self sharedInstance];
}

// 防止拷贝
- (id)copyWithZone:(NSZone *)zone {
    return self;
}
四、性能对比
实现方案 线程安全 时间复杂度 内存屏障
@synchronized O(n)
dispatch_once O(1)
双重检查锁定 O(1)

最佳实践

  1. 始终使用 dispatch_once 方案
  2. .m 文件中声明静态变量而非头文件
  3. 重写 allocWithZone:copyWithZone: 方法
  4. 避免在单例初始化方法中调用 sharedInstance
五、使用场景

适合以下全局服务:

  • 配置管理器
  • 网络监控器
  • 核心数据栈
  • 日志系统
graph LR A[调用 sharedInstance] --> B{实例是否存在?} B -- 否 --> C[dispatch_once 创建] B -- 是 --> D[返回现存实例] C --> D

此方案满足: $$ \forall t \in \mathbb{T}, \quad \exists! , \text{instance} \in \text{MySingleton} $$ 其中 \\mathbb{T} 表示线程集合,\\exists! 表示存在且唯一。

相关推荐
是一个Bug几秒前
Java后端开发面试题清单(50道)
java·开发语言·jvm
GIS 数据栈2 分钟前
【Seggis遥感系统升级】用C++高性能服务Drogon重构软件服务架构|QPS提升300%,性能再升级!
java·开发语言·c++·重构·架构
moxiaoran57533 分钟前
Go语言的接口
开发语言·后端·golang
浮尘笔记15 分钟前
Go语言中的同步等待组和单例模式:sync.WaitGroup和sync.Once
开发语言·后端·单例模式·golang
lsx20240618 分钟前
C++ 变量作用域
开发语言
TESmart碲视22 分钟前
M4芯片MacBook支持多显示器吗?mac如何与KVM切换器使用。
macos·计算机外设·mst·kvm切换器·双屏kvm切换器
小鸡脚来咯22 分钟前
设计模式面试介绍指南
java·开发语言·单例模式
小北方城市网22 分钟前
GEO 全场景智能生态:自适应架构重构与极限算力协同落地
开发语言·人工智能·python·重构·架构·量子计算
我的golang之路果然有问题30 分钟前
Mac 上的 Vue 安装和配置记录
前端·javascript·vue.js·笔记·macos
十五年专注C++开发31 分钟前
CMake进阶:核心命令get_filename_component 完全详解
开发语言·c++·cmake·跨平台编译