一侍瑟、單線程模式單例
// 單線程單例
+(instancetype)sharedLoadData
{
static Singleton *singleton;
if (!singleton ) {
singleton = [[Singleton alloc] init];
}
return singleton;
}
- 單線程單例只有在單個線程使用的情況下實用,在多線程的情況下丙猬,會產(chǎn)生線程不安全的情況涨颜。嚴格意義上來說,我們還需要把alloc方法變?yōu)樗接蟹椒ú判屑肭颍瑖栏竦膯卫遣辉试S再創(chuàng)建其他實例的庭瑰,而alloc方法可以在外部任意生成實例。換句話說袜腥,假如在兩條線程里調(diào)用sharedLoadData方法见擦,可能會產(chǎn)生兩個singleton實例,這樣單例就失去意義了羹令。
二鲤屡、多線程加鎖單例
// @synchronized加鎖
+(instancetype)sharedLoadData
{
static Singleton *singleton;
@synchronized (self) {
if (!singleton) {
singleton = [[Singleton alloc] init];
}
}
return singleton;
}
- 加鎖以后,當(dāng)多個線程同時調(diào)用shareInstance時福侈,由于@synchronized已經(jīng)加鎖酒来,只能有一個線程創(chuàng)建singleton實例。這樣就解決了第一種情況的弊端肪凛。
但是也有缺點:只有在singleton未創(chuàng)建時堰汉,加鎖才是必要的。如果singleton已經(jīng)創(chuàng)建伟墙,這個時候還加鎖的話翘鸭,會影響性能。
三戳葵、系統(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時,線程執(zhí)行dispatch_once的block中代碼
2.當(dāng)onceToken = -1時邦投,線程跳過dispatch_once的block中代碼不執(zhí)行
3.當(dāng)onceToken為其他值時伤锚,線程被阻塞,等待onceToken值改變當(dāng)線程調(diào)用shareInstance,此時onceToken = 0志衣,調(diào)用block中的代碼屯援,此時onceToken的值變?yōu)?40734537148864。當(dāng)其他線程再調(diào)用shareInstance方法時蠢涝,onceToken的值已經(jīng)是140734537148864了玄呛,線程阻塞。當(dāng)block線程執(zhí)行完block之后和二,onceToken變?yōu)?1.其他線程不再阻塞徘铝,跳過block。下次再調(diào)用shareInstance時惯吕,block已經(jīng)為-1.直接跳過block惕它。