線程安全---鎖

前言

線程安全是IOS開發(fā)中避免不了的話題刹碾,隨著多線程的使用废膘,對于資源的競爭以及數(shù)據(jù)的操作都可能存在風(fēng)險,所以有必要在操作時保證線程安全鲫骗。線程安全是多線程技術(shù)的保障沈贝,而IOS中實(shí)現(xiàn)線程安全主要是依靠各種鎖杠人,鎖的種類很多,各有各的優(yōu)缺點(diǎn)宋下,需要開發(fā)者在使用過程中權(quán)衡利弊嗡善,選擇最合適的鎖來搭配多線程技術(shù)。

鎖的種類:

NSLock

synchronized
pthread
信號量
NSConditionLock 與NSCondition
自旋鎖
遞歸鎖
隨著項(xiàng)目越來越龐大且越來越復(fù)雜学歧,對于項(xiàng)目中事務(wù)的處理罩引,多線程的使用也變得尤為必要。多線程利用了CPU多核的性質(zhì)枝笨,能并行執(zhí)行任務(wù)袁铐,提高效率,單是隨之而來的也會出現(xiàn)一些由多線程使用而造成的問題横浑。鎖主要分為:互斥鎖剔桨,遞歸鎖,信號量徙融,條件鎖 等... 鎖的功能就是為了防止不同線程同時訪問一段代碼洒缀。下面舉個簡單的例子。
創(chuàng)建一個Pesson類 其中有一個NSinteger 屬性 類型屬性age
#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Person : NSObject

@property (nonatomic , assign)NSInteger age; //在為賦值情況下 age默認(rèn)是0 在外部模擬一種多線程的方位實(shí)例方法的情況

@end

NS_ASSUME_NONNULL_END

- (void)withoutLock {
    
  __block  Person *p = [Person  new];
    
    [NSThread detachNewThreadWithBlock:^{
        
        for (int i = 0; i< 1000; i++) {
            p.age++;
        }
        NSLog(@"%ld \n",p.age);
        
    }];
    
    
    [NSThread detachNewThreadWithBlock:^{
        for (int i = 0; i< 1000; i++) {
            p.age++;
        }
        NSLog(@"%ld \n",p.age);
    }];
    
}
不要在意數(shù)值的大小欺冀,這里只是為了達(dá)到模擬效果树绩。可以看出隐轩,有兩處代碼饺饭,在不同的線程中調(diào)用了p.aee++; 按理想情況來說 結(jié)果應(yīng)該是p.age是2000,但是分別打印線程的代碼執(zhí)行完后并非如此(每次執(zhí)行結(jié)果基本都不相同)因?yàn)槭遣煌木€程职车,所以不確定哪一個會先執(zhí)行結(jié)束瘫俊。相信有一定基礎(chǔ)的同學(xué)都會明白其原因。因?yàn)樵谠撎幏椒ㄖ袥]有加鎖悴灵,導(dǎo)致不同線程競爭資源军援。當(dāng)a線程和b線程同時拿到age時,例如此時的age的值是100 執(zhí)行自增之后 a線程和b線程都將101賦值給了age,但總得有個先來后到称勋,結(jié)果就是某一次被覆蓋了胸哥。多次這樣的操作就會導(dǎo)致誤差。這個時候在多線程訪問同一資源時要通過鎖來保證同一時間僅有一個線程對該資源訪問赡鲜,這樣就可以避免上述問題的發(fā)生空厌!
1.使用 NSLock
- (void)withoutLock {
    
  __block  Person *p = [Person  new];
    
    NSLock *lock = [[NSLock alloc] init]; //加鎖
    
    [NSThread detachNewThreadWithBlock:^{
        
        for (int i = 0; i< 1000; i++) {
            [lock lock];
            p.age++;
            [lock unlock];
        }
        NSLog(@"%ld \n",p.age);
        
    }];
    
    
    [NSThread detachNewThreadWithBlock:^{
        for (int i = 0; i< 1000; i++) {
            [lock lock];
            p.age++;
            [lock unlock];
        }
        NSLog(@"%ld \n",p.age);
    }];
    
}
NSLock使用起來比較簡單,用創(chuàng)建的實(shí)例對象調(diào)用lock和unlock方法來加鎖解鎖银酬,通過答應(yīng)可以看到 結(jié)果是正確的 最后age是2000.
2.使用synchronized
這種鎖是比較常用的嘲更,因?yàn)槠涫褂梅椒ㄊ撬枣i中最簡單的,但性能卻是最差的揩瞪,所以對性能要求不太的使用情景下使用synchronized不失為一種比較方便的鎖 代碼如下赋朦。
- (void)synchronizedTest {
    
    __block  Person *p = [Person  new];
      
      [NSThread detachNewThreadWithBlock:^{
          
          for (int i = 0; i< 1000; i++) {
              @synchronized (p) { //加鎖
                  p.age++;
              }
          }
          NSLog(@"%ld \n",p.age);
          
      }];
      
      
      [NSThread detachNewThreadWithBlock:^{
          for (int i = 0; i< 1000; i++) {
              @synchronized (p) { //加鎖
                  p.age++;
              }
          }
          NSLog(@"%ld \n",p.age);
      }];
}

可以看出不需要創(chuàng)建鎖,類似Swift中調(diào)用一個含有尾隨閉包的函數(shù),就能實(shí)現(xiàn)功能宠哄。
synchronized內(nèi)部實(shí)現(xiàn)是通過傳入對象壹将,為其分配一個遞歸鎖,存儲在哈希表中毛嫉。使用synchronized還需要有一些注意的地方诽俯,除了性能方面有劣勢 還有兩個問題, 一個是小括號里面需要傳一個對象類型承粤,基本數(shù)據(jù)類型不能作為參數(shù), 另一個是小括號內(nèi)的對象不能為空暴区,如果為nil 就不能保證其鎖的功能。

3. pthread 的全稱是POSIX thread 是一套跨平臺的多線程API,各個平臺對其都有實(shí)現(xiàn)辛臊。pthread 是一套非常強(qiáng)大的多線程鎖仙粱,可以創(chuàng)建互斥鎖 ,遞歸鎖 彻舰,信號量伐割,條件鎖,讀寫鎖淹遵,once鎖等口猜,基本上所有涉及的鎖,都可以用pthread來實(shí)現(xiàn)

- (void)ptheadNormalTest {
    
    __block Person *p = [[Person alloc] init];
    
    NSLog(@"begin");
    
    __block pthread_mutex_t t;
    
    pthread_mutex_init(&t,NULL);
    
    [NSThread detachNewThreadWithBlock:^{
        
        for (int i = 0; i< 1000; i++) {
            pthread_mutex_lock(&t);
            p.age++;
            pthread_mutex_unlock(&t);
        }
        NSLog(@"% zd \n",p.age);
    }];
    
    [NSThread detachNewThreadWithBlock:^{
        
        for (int i = 0; i< 1000; i++) {
            pthread_mutex_lock(&t);
            p.age++;
            pthread_mutex_unlock(&t);
        }
        NSLog(@"% zd \n",p.age);
    }];
    
//    pthread_mutex_destroy(&t);
}

未完后續(xù)會補(bǔ)充透揣!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末济炎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子辐真,更是在濱河造成了極大的恐慌须尚,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件侍咱,死亡現(xiàn)場離奇詭異耐床,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)楔脯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門撩轰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昧廷,你說我怎么就攤上這事堪嫂。” “怎么了木柬?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵皆串,是天一觀的道長。 經(jīng)常有香客問我眉枕,道長恶复,這世上最難降的妖魔是什么怜森? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮谤牡,結(jié)果婚禮上副硅,老公的妹妹穿的比我還像新娘。我一直安慰自己拓哟,他們只是感情好想许,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布伶授。 她就那樣靜靜地躺著断序,像睡著了一般。 火紅的嫁衣襯著肌膚如雪糜烹。 梳的紋絲不亂的頭發(fā)上违诗,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天,我揣著相機(jī)與錄音疮蹦,去河邊找鬼诸迟。 笑死,一個胖子當(dāng)著我的面吹牛愕乎,可吹牛的內(nèi)容都是我干的阵苇。 我是一名探鬼主播,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼感论,長吁一口氣:“原來是場噩夢啊……” “哼绅项!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起比肄,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤快耿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后芳绩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掀亥,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年妥色,在試婚紗的時候發(fā)現(xiàn)自己被綠了搪花。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡嘹害,死狀恐怖撮竿,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吼拥,我是刑警寧澤倚聚,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站凿可,受9級特大地震影響惑折,放射性物質(zhì)發(fā)生泄漏授账。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一惨驶、第九天 我趴在偏房一處隱蔽的房頂上張望白热。 院中可真熱鬧,春花似錦粗卜、人聲如沸屋确。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽攻臀。三九已至,卻和暖如春纱昧,著一層夾襖步出監(jiān)牢的瞬間刨啸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工识脆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留设联,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓灼捂,卻偏偏與公主長得像离例,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子悉稠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評論 2 355