object-c 單例模式的執行緒安全
阿新 • • 發佈:2019-01-30
單例模式(Singleton Pattern):保證一個類只有一個例項,並且提供一個訪問它的全域性訪問點。
單例在程式設計中是最常見的設計模式之一,下面我們來實現一個單例:
Singleton.h 檔案
#import <Foundation/Foundation.h>
@interface Singleton : NSObject
+ (instancetype) shareInstance;
@end
Singleton.m 檔案
static Singleton * singleton = nil;
@implementation Singleton
+ (instancetype) shareInstance {
return [self allocWithZone:nil];
}
+(id)allocWithZone:(NSZone *)zone{
if (!singleton) {
singleton = [[super alloc] init];
}
return singleton;
}
- (id)copyWithZone:(NSZone *)zone;{
return self ;
}
這樣寫好像就能夠實現單例模式,但是我們要想,它真的能夠保證程式中只有一個單例類的物件麼?答案顯然是否定的。當shareInstance方法第一次呼叫沒有完成的時候,單例物件還是nil,這時候如果另外一個執行緒在此呼叫shareInstance方法會發生什麼呢?顯然,這個時候系統會初始化兩次單例物件,也就是說這個時候不是單例了,因為這時候的單例類已經不止一個例項物件了。那麼怎麼才能保證單例的執行緒安全呢,這就是線面要實現的:
方法一:加執行緒鎖
對單例物件初始化方法新增執行緒鎖,當其他執行緒在此訪問時執行緒鎖能夠保證單例物件在初始化完成之前不能再次呼叫初始化方法。
#import "Singleton.h"
static Singleton * singleton = nil;
@implementation Singleton
+ (instancetype) shareInstance {
return [self allocWithZone:nil];
}
+(id)allocWithZone:(NSZone *)zone{
@synchronized(self){
if (!singleton) {
singleton = [[Singleton alloc] init];
}
}
return singleton;
}
- (id) copyWithZone:(NSZone *)zone;{
return self;
}
方法二:GCD實現
gcd 中dispatch_once函式在程式執行中僅執行一次,且執行緒安全,所以也能夠用它實現單例的執行緒安全
#import "Singleton.h"
static Singleton * singleton = nil;
@implementation Singleton
+ (instancetype)allocWithZone:(struct _NSZone *)zone
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singleton = [super allocWithZone:zone];
});
return singleton;
}
+ (instancetype) shareInstance {
return [self allocWithZone:nil];
}
- (id) copyWithZone:(NSZone *)zone;{
return self;
}