以前在Java、C#等語言中,我們實現遲緩加載的單例模式一般寫成如下形式(偽代碼):
private MyClass() {...} // 私有化構造方法
private static MyClass instance; // 承載對象的變量
pubic static MyClass getInstance() { // 完成實例化任務
if (instance == null) { // 第一次判斷
lock (obj) { // 加鎖,處理多線程判斷
if (instance == null) {// 再次判斷,避免線程切換導致多個實例對象出現
instance = new MyClass(); // 完成最終實例化過程
}
}
}
return instance;
}
但是,在Objective-C中經常看到的卻是這種寫法:
+ (instancetype)sharedInstance {
static id sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self new];
});
return sharedInstance;
}
這種寫法似乎並沒對多線程編程作防御性處理。其實,dispatch_once是線程安全的,即使在多個線程中同時調用,也只有一個塊被執行,其它dispatch_once塊的調用被阻塞,直到執行的那個塊運行結束,所以在整個程序運行周期內,dispatch_once塊只會運行一次,可以確定,下一行代碼執行前,整個dispatch_once塊是執行完畢的,不管當前工作線程是哪個。如果已執行,dispatch_once會被快速跳過,在類似循環體中調用這種場合,也無需擔心執行它的額外性能開銷。如果一個程序包含多個同一調用類的實例,只有其中一個實例會執行dispatch_once塊[1]。