一奏瞬、單線程模式單例
// 單線程單例
+(instancetype)sharedLoadData
{
static Singleton *singleton;
if (!singleton ) {
singleton = [[Singleton alloc] init];
}
return singleton;
}
· 單線程單例只有在單個(gè)線程使用的情況下實(shí)用侄刽,在多線程的情況下衷模,會(huì)產(chǎn)生線程不安全的情況鹊汛。嚴(yán)格意義上來(lái)說(shuō),我們還需要把a(bǔ)lloc方法變?yōu)樗接蟹椒ú判汹逡保瑖?yán)格的單例是不允許再創(chuàng)建其他實(shí)例的刁憋,而alloc方法可以在外部任意生成實(shí)例。換句話說(shuō)木蹬,假如在兩條線程里調(diào)用sharedLoadData方法至耻,可能會(huì)產(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í)候還加鎖的話尤莺,會(huì)影響性能。
三生棍、系統(tǒng)GCD創(chuàng)建單例
+(instancetype)sharedLoadData
{
static Singleton *singleton = nil;
static dispatch_once_t onceToken;
// dispatch_once 無(wú)論使用多線程還是單線程颤霎,都只執(zhí)行一次
dispatch_once(&onceToken, ^{
singleton = [[Singleton alloc] init];
});
return singleton;
}
· GCD創(chuàng)建單例不僅可以解決多條線程的線程安全問(wèn)題,也能保證性能足绅,是官方推薦的方式捷绑。
· dispatch_once主要是根據(jù)onceToken的值來(lái)決定怎么去執(zhí)行代碼。
1.當(dāng)onceToken = 0時(shí)氢妈,線程執(zhí)行dispatch_once的block中代碼
2.當(dāng)onceToken = -1時(shí)粹污,線程跳過(guò)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.其他線程不再阻塞杠人,跳過(guò)block。下次再調(diào)用shareInstance時(shí)宋下,block已經(jīng)為-1.直接跳過(guò)block嗡善。