一、單線程模式單例
// 單線程單例
+(instancetype)sharedLoadData
{
static Singleton *singleton;
if (!singleton ) {
singleton = [[Singleton alloc] init];
}
return singleton;
}
- 單線程單例只有在單個(gè)線程使用的情況下實(shí)用,在多線程的情況下,會產(chǎn)生線程不安全的情況。嚴(yán)格意義上來說,我們還需要把a(bǔ)lloc方法變?yōu)樗接蟹椒ú判校瑖?yán)格的單例是不允許再創(chuàng)建其他實(shí)例的,而alloc方法可以在外部任意生成實(shí)例。換句話說,假如在兩條線程里調(diào)用sharedLoadData方法,可能會產(chǎn)生兩個(gè)singleton實(shí)例,這樣單例就失去意義了。
二、多線程加鎖單例
// @synchronized加鎖
+(instancetype)sharedLoadData
{
static Singleton *singleton;
@synchronized (self) {
if (!singleton) {
singleton = [[Singleton alloc] init];
}
}
return singleton;
}
- 加鎖以后,當(dāng)多個(gè)線程同時(shí)調(diào)用shareInstance時(shí),由于@synchronized已經(jīng)加鎖,只能有一個(gè)線程創(chuàng)建singleton實(shí)例。這樣就解決了第一種情況的弊端。
但是也有缺點(diǎn):只有在singleton未創(chuàng)建時(shí),加鎖才是必要的。如果singleton已經(jīng)創(chuàng)建,這個(gè)時(shí)候還加鎖的話,會影響性能。
三、系統(tǒng)GCD創(chuàng)建單例
+(instancetype)sharedLoadData
{
static Singleton *singleton = nil;
static dispatch_once_t onceToken;
// dispatch_once 無論使用多線程還是單線程,都只執(zhí)行一次
dispatch_once(&onceToken, ^{
singleton = [[Singleton alloc] init];
});
return singleton;
}
GCD創(chuàng)建單例不僅可以解決多條線程的線程安全問題,也能保證性能,是官方推薦的方式。
dispatch_once主要是根據(jù)onceToken的值來決定怎么去執(zhí)行代碼。
1.當(dāng)onceToken = 0時(shí),線程執(zhí)行dispatch_once的block中代碼
2.當(dāng)onceToken = -1時(shí),線程跳過dispatch_once的block中代碼不執(zhí)行
3.當(dāng)onceToken為其他值時(shí),線程被阻塞,等待onceToken值改變當(dāng)線程調(diào)用shareInstance,此時(shí)onceToken = 0,調(diào)用block中的代碼,此時(shí)onceToken的值變?yōu)?40734537148864。當(dāng)其他線程再調(diào)用shareInstance方法時(shí),onceToken的值已經(jīng)是140734537148864了,線程阻塞。當(dāng)block線程執(zhí)行完block之后,onceToken變?yōu)?1.其他線程不再阻塞,跳過block。下次再調(diào)用shareInstance時(shí),block已經(jīng)為-1.直接跳過block。