IOS nonatomic 與atomic 分析

在實際的開發(fā)中遇到了一個有趣的問題,在我用 nonatomic 定義的對象中

@property (nonatomic, strong) 
image.png

出現(xiàn)了崩潰哗伯,崩潰原因是在子線程Thread4上晶乔,對象釋放了。于是果然重寫他的setter方法來查看問題:

- (void)setFunction:(NSString *)function
{
    if (_function != function) {
        _function = function;
    }
}

再修改了setter方法之后發(fā)現(xiàn)依然崩潰:


image.png

這次是在Thread2 中發(fā)現(xiàn)了崩潰,多運行幾次發(fā)現(xiàn)這些崩潰線程是無序的,果然該問題是與線程有關(guān)。
我們新建個項目來分析遇到的這個問題,

@property (nonatomic, strong) NSString *function;

for (NSInteger i = 0; i < 10000; i++) {
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            self.function = [NSString stringWithFormat:@"fucntion:%ld", i];
        });
    }

通過異步線程反復(fù)執(zhí)行發(fā)現(xiàn),果然與我們遇到的問題相同,對象被提前釋放了,可是我們的setter方法中并沒有釋放過對象,深入研究后發(fā)現(xiàn)原來在MRC上setter方法如下:

-(void)setFunction:(NSString *)function{
    if (_function != function) {
        [_function release];
        [function retain];
        _function = function;
    }
}

這說明 雖然在ARC模式下不用寫其set方法,但是在我們執(zhí)行setter方法的時候還是會和ARC相同蔓榄。
因為是多線程,且沒有加鎖保護默刚,所以在一個線程走到[_function release]后甥郑,可能在另一個線程又一次去釋放,這時候造成崩潰荤西。
果斷改變思路將修飾符改成了atomic澜搅,發(fā)現(xiàn)此時已經(jīng)不崩潰了伍俘。

那么問題來了,使用atomic就是絕對的線程安全么?

@property (atomic, assign) int number;
//線程1
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    for (int i = 0; i < 10000; i ++){
        self.number = self.number + 1;
        NSLog(@"Thread 1: %d\n", self.number);
    }
});
    
    //線程2
dispatch_async(dispatch_get_global_queue(0, 0), ^{
    for (int i = 0; i < 10000; i ++){
        self.number = self.number + 1;
        NSLog(@"Thread 2: %d\n", self.number);
     }
 });

看console下執(zhí)行完畢的最后一行,如果是絕對的線程安全,即使在異步線程下,最后一遍執(zhí)行的NSLog 出來的number值也應(yīng)該是是20000 才對,直接看控制臺的結(jié)果:

2020-04-01 14:05:19.671949+0800 copy[29072:2224902] Thread 1: 18161

為什么結(jié)果是18161勉躺,多執(zhí)行幾次后發(fā)現(xiàn)最后一次輸出的是無序的數(shù)字癌瘾。
所以線程是不安全的。thread1 在執(zhí)行表達式 self.number之后 self.number = self.number + 1;并沒有執(zhí)行完畢饵溅。此時thread2 執(zhí)行self.number = self.number + 1;再回到thread1時妨退,self.number的數(shù)值就被更新了;所以僅僅使用atomic并不能保證線程安全概说。
atomic 只能保證屬性的存取方法是線程安全的,多線程下將屬性設(shè)置為atomic可以保證讀取數(shù)據(jù)的一致性碧注。因為他將保證數(shù)據(jù)只能被一個線程占用嚣伐,也就是說一個線程對屬性進行寫操作時糖赔,會使用自旋鎖鎖住該屬性。不允許其他的線程對其進行讀取操作了轩端。而且因為atomic要使用自旋鎖鎖住該屬性放典,因此它會消耗更多的資源,性能會很低基茵。要比nonatomic慢20倍奋构。

所以我們需要對線程安全時需要怎么做:

NSLock

    NSLock *_lock = [[NSLock alloc] init];
    //線程1
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [_lock lock];
        for (int i = 0; i < 10000; i ++){
            self.number = self.number + 1;
            NSLog(@"Thread 1: %d\n", self.number);
        }
        [_lock unlock];
    });
    
    //線程2
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        [_lock lock];
        for (int i = 0; i < 10000; i ++){
            self.number = self.number + 1;
            NSLog(@"Thread 2: %d\n", self.number);
        }
        [_lock unlock];
    });

再看輸出框 果然和我們預(yù)想的一樣:


image.png

同樣的方法還有以下:
os_unfair_lock(推薦??????????)
OSSpinLock(不安全????)
dispatch_semaphore(推薦??????????)
pthread_mutex(推薦????????)
dispatch_queue(DISPATCH_QUEUE_SERIAL)(推薦??????)
NSLock(??????)
NSCondition(??????)
pthread_mutex(recursive)(????)
NSRecursiveLock(????)
NSConditionLock(????)
@synchronized(最不推薦)

使用方式可以看: 如何保證iOS的多線程安全)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拱层,隨后出現(xiàn)的幾起案子弥臼,更是在濱河造成了極大的恐慌,老刑警劉巖根灯,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件径缅,死亡現(xiàn)場離奇詭異,居然都是意外死亡烙肺,警方通過查閱死者的電腦和手機纳猪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桃笙,“玉大人氏堤,你說我怎么就攤上這事〔鳎” “怎么了鼠锈?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長星著。 經(jīng)常有香客問我脚祟,道長,這世上最難降的妖魔是什么强饮? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任由桌,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘行您。我一直安慰自己铭乾,他們只是感情好,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布娃循。 她就那樣靜靜地躺著炕檩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捌斧。 梳的紋絲不亂的頭發(fā)上笛质,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天,我揣著相機與錄音捞蚂,去河邊找鬼妇押。 笑死,一個胖子當著我的面吹牛姓迅,可吹牛的內(nèi)容都是我干的敲霍。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼丁存,長吁一口氣:“原來是場噩夢啊……” “哼肩杈!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起解寝,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤扩然,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后聋伦,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夫偶,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年嘉抓,在試婚紗的時候發(fā)現(xiàn)自己被綠了索守。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡抑片,死狀恐怖卵佛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情敞斋,我是刑警寧澤截汪,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站植捎,受9級特大地震影響衙解,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜焰枢,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一蚓峦、第九天 我趴在偏房一處隱蔽的房頂上張望舌剂。 院中可真熱鬧,春花似錦暑椰、人聲如沸霍转。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽避消。三九已至,卻和暖如春召夹,著一層夾襖步出監(jiān)牢的瞬間岩喷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工监憎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留纱意,地道東北人。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓枫虏,卻偏偏與公主長得像妇穴,于是被迫代替她去往敵國和親爬虱。 傳聞我的和親對象是個殘疾皇子隶债,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 1.設(shè)計模式是什么? 你知道哪些設(shè)計模式跑筝,并簡要敘述死讹? 設(shè)計模式是一種編碼經(jīng)驗,就是用比較成熟的邏輯去處理某一種類...
    司馬DE晴空閱讀 1,278評論 0 7
  • 本文用來介紹 iOS 多線程中 GCD 的相關(guān)知識以及使用方法曲梗。這大概是史上最詳細赞警、清晰的關(guān)于 GCD 的詳細講...
    花花世界的孤獨行者閱讀 495評論 0 1
  • 1.傳統(tǒng)上一般以為,人腦子里的認識是跟著外部世界的現(xiàn)實變的虏两。但尤瓦爾·赫拉利偏偏要說愧旦,真相也許是,人類腦子里的共識...
    會飛的貓666閱讀 287評論 0 0
  • 圖文|武姿仙居 車來了定罢,趕緊拎著兩包東西上了車笤虫,對于我來說這兩包東西還聽重的。拎得我的手都酸了祖凫。好心的售票員姐姐幫...
    夢姿書齋閱讀 244評論 2 3
  • 運行時數(shù)據(jù)區(qū)域 Java虛擬機在執(zhí)行Java程序的過程中會把它所管理的內(nèi)存劃分為若干個不同的數(shù)據(jù)區(qū)域琼蚯。這些區(qū)域都有...
    不要戒酒閱讀 291評論 0 1