iOS 之 線程鎖

一般情況下猎唁,我們定義屬性的時(shí)候都是這樣定義的:

@property (nonatomic, copy) NSString *string1;
@property (nonatomic, strong) NSMutableString *string2;

copystrong的區(qū)別就不在這里多說(shuō)了发笔,主要來(lái)看下這個(gè)nonatomic以及atomic

nonatomic & atomic

atomic和nonatomic用來(lái)決定編譯器生成的getter和setter是否為原子操作联予。這里是指系統(tǒng)自動(dòng)生成的 getter/setter 方法淳梦。如果自己重寫 getter/setter方法躺涝,那atomic/nonatomic只起提示作用

  • atomic:提供多線程安全
    設(shè)置成員變量的@property屬性時(shí)疗我,默認(rèn)為atomic,提供多線程安全琐脏。相當(dāng)于函數(shù)頭尾加了鎖一樣攒砖,可以保證數(shù)據(jù)的完整性缸兔。而這種機(jī)制是耗費(fèi)系統(tǒng)資源的。
{lock}
if (property != newValue) { 
    [property release]; 
    property = [newValue retain]; 
}
{unlock}
  • nonatomic:禁止多線程吹艇,變量保護(hù)惰蜜,提高性能。
    一般iOS程序中受神,所有屬性都聲明為nonatomic抛猖。這樣做的原因是:在iOS中使用同步鎖的開(kāi)銷比較大, 這會(huì)帶來(lái)性能問(wèn)題鼻听。一般情況下并不要求屬性必須是“原子的”财著,因?yàn)檫@并不能保證“線程安全”(thread safety),若要實(shí)現(xiàn)“線程安全”的操作撑碴,還需采用更為深層的鎖定機(jī)制才醒撑教。

于是引出了本篇的話題:線程鎖

線程鎖

多線程編程中,應(yīng)該盡量避免資源在線程之間共享醉拓,以減少線程間的相互作用伟姐。 但是總是有多個(gè)線程相互干擾的情況(如多個(gè)線程訪問(wèn)一個(gè)資源)。在線程必須交互的情況下亿卤,就需要一些同步工具愤兵,來(lái)確保當(dāng)它們交互的時(shí)候是安全的。

簡(jiǎn)單來(lái)說(shuō):我們引入鎖的目的是為了線程安全怠噪。

image

找到一張關(guān)于線程鎖性能的比較圖片恐似,如圖所示

性能最好的是OSSpinLock(據(jù)說(shuō)是不安全的的杜跷,詳情請(qǐng)看ibireme大神的不再安全的 OSSpinLock)

我們一起來(lái)看下在iOS開(kāi)發(fā)中常用的幾種鎖

1. @synchronized

推薦文章:
Peak大神正確使用多線程同步鎖@synchronized()
關(guān)于 @synchronized傍念,這兒比你想知道的還要多
@synchronized 結(jié)構(gòu)所做的事情跟鎖(lock)類似:它防止不同的線程同時(shí)執(zhí)行同一段代碼。@synchronized是幾種iOS多線程同步機(jī)制中最慢的一個(gè)葛闷,同時(shí)也是最方便的一個(gè)憋槐。蘋果建立@synchronized的初衷就是方便開(kāi)發(fā)者快速的實(shí)現(xiàn)代碼同步,語(yǔ)法如下:

@synchronized(object) {
  //code
}

Peak大神在文章中提醒我們:

  • 慎用@synchronized(self)
    synchronized中傳入的object的內(nèi)存地址淑趾,被用作key阳仔,通過(guò)hash map對(duì)應(yīng)的一個(gè)系統(tǒng)維護(hù)的遞歸鎖。不管是傳入什么類型的object扣泊,只要是有內(nèi)存地址近范,就能啟動(dòng)同步代碼塊的效果。
  • 粒度控制延蟹,不同的數(shù)據(jù)使用不同的鎖评矩,盡量將粒度控制在最細(xì)的程度
    有些人說(shuō)@synchronized慢,但@synchronized之所以慢是更多的因?yàn)闆](méi)有做好粒度控制阱飘。鎖本質(zhì)上是為了讓我們的一段代碼獲得原子性斥杜,不同的critical section要使用不同的鎖虱颗。

@synchronized也經(jīng)常用來(lái)實(shí)現(xiàn)單例,用的更多的還是GCD中的一次函數(shù)dispatch_once蔗喂,關(guān)于@synchronized和dispatch_once的性能比較忘渔,有興趣的童鞋們可以看這里

2. NS系列鎖

NS系列鎖指的是NSLockNSCondition缰儿、NSConditionLock畦粮、NSRecursiveLock,之所以把這幾個(gè)放在一起乖阵,是因?yàn)樗鼈兌甲袷?code>NSLocking協(xié)議锈玉,就倆方法,加鎖解鎖义起,so easy拉背!

@protocol NSLocking
- (void)lock;
- (void)unlock;
@end
2.1 NSLock 線程鎖

看下NSLock 的API,嗯默终,很少也很簡(jiǎn)單:

@interface NSLock : NSObject <NSLocking> {
@private
    void *_priv;
}
- (BOOL)tryLock;
- (BOOL)lockBeforeDate:(NSDate *)limit;

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

@end

方法說(shuō)明:
trylock:能加鎖返回 YES 并執(zhí)行加鎖操作椅棺,相當(dāng)于 lock,反之返回 NO
lockBeforeDate:這個(gè)方法表示會(huì)在傳入的時(shí)間內(nèi)嘗試加鎖齐蔽,若能加鎖則執(zhí)行加鎖操作并返回 YES两疚,反之返回 NO。

2.2 NSConditionLock 條件鎖

condition:條件含滴,顧名思義NSConditionLock就是有條件的加鎖诱渤,繼續(xù)來(lái)看API

@interface NSConditionLock : NSObject <NSLocking> {
@private
    void *_priv;
}

- (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER;

@property (readonly) NSInteger condition;
- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

@end

比較了一下,貌似跟NSLock差不多谈况,只是加了個(gè)condition勺美,還是NSInteger類型的,感覺(jué)只要把這個(gè)參數(shù)搞明白就差不多了碑韵。
condition我們可以理解為一個(gè)條件標(biāo)示赡茸,看下創(chuàng)建方法:initWithCondition:創(chuàng)建的時(shí)候傳入一個(gè)條件標(biāo)識(shí),之后如果使用創(chuàng)建好的鎖祝闻,必須傳入對(duì)應(yīng)的標(biāo)識(shí)才能完成對(duì)應(yīng)的lock和unlock操作

2.3 NSRecursiveLock 遞歸鎖
@interface NSRecursiveLock : NSObject <NSLocking> {
@private
    void *_priv;
}

- (BOOL)tryLock;
- (BOOL)lockBeforeDate:(NSDate *)limit;

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

@end
2.4 NSCondition 斷言
@interface NSCondition : NSObject <NSLocking> {
@private
    void *_priv;
}

- (void)wait;
- (BOOL)waitUntilDate:(NSDate *)limit;
- (void)signal;
- (void)broadcast;

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

@end

3. dispatch_semaphore 信號(hào)量實(shí)現(xiàn)加鎖(GCD)

之前寫過(guò)一篇dispatch_semaphore信號(hào)量的文章占卧,麻煩大家手動(dòng)移駕過(guò)去。

我自己測(cè)試的線程鎖的性能如下:


image.png

推薦文章(排名不分先后):
(ibireme大神的不再安全的 OSSpinLock)
http://www.reibang.com/p/1e59f0970bf5

關(guān)于遞歸鎖與非遞歸鎖联喘,平常接觸比較少华蜒,有興趣的童鞋可以了解一下:https://blog.csdn.net/zouxinfox/article/details/5838861

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市豁遭,隨后出現(xiàn)的幾起案子叭喜,更是在濱河造成了極大的恐慌,老刑警劉巖堤框,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件域滥,死亡現(xiàn)場(chǎng)離奇詭異纵柿,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)启绰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門昂儒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人委可,你說(shuō)我怎么就攤上這事渊跋。” “怎么了着倾?”我有些...
    開(kāi)封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵拾酝,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我卡者,道長(zhǎng)蒿囤,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任崇决,我火速辦了婚禮材诽,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恒傻。我一直安慰自己脸侥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布盈厘。 她就那樣靜靜地躺著睁枕,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沸手。 梳的紋絲不亂的頭發(fā)上外遇,一...
    開(kāi)封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音罐氨,去河邊找鬼臀规。 笑死,一個(gè)胖子當(dāng)著我的面吹牛栅隐,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玩徊,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼租悄,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了恩袱?” 一聲冷哼從身側(cè)響起泣棋,我...
    開(kāi)封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎畔塔,沒(méi)想到半個(gè)月后潭辈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體鸯屿,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年把敢,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了寄摆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡修赞,死狀恐怖婶恼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情柏副,我是刑警寧澤勾邦,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站割择,受9級(jí)特大地震影響眷篇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荔泳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一铅歼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧换可,春花似錦椎椰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至译荞,卻和暖如春瓤的,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背吞歼。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工圈膏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人篙骡。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓稽坤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親糯俗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尿褪,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

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

  • 前言 iOS開(kāi)發(fā)中由于各種第三方庫(kù)的高度封裝,對(duì)鎖的使用很少得湘,剛好之前面試中被問(wèn)到的關(guān)于并發(fā)編程鎖的問(wèn)題杖玲,都是一知...
    喵渣渣閱讀 3,703評(píng)論 0 33
  • 拋磚引玉 說(shuō)到鎖不得不提線程安全,說(shuō)到線程安全淘正,作為iOS程序員又不得不提 nonatomic 與 atomic ...
    Inlight先森閱讀 2,050評(píng)論 0 23
  • 鎖是一種同步機(jī)制摆马,用于多線程環(huán)境中對(duì)資源訪問(wèn)的限制iOS中常見(jiàn)鎖的性能對(duì)比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,518評(píng)論 0 6
  • 線程安全是怎么產(chǎn)生的 常見(jiàn)比如線程內(nèi)操作了一個(gè)線程外的非線程安全變量臼闻,這個(gè)時(shí)候一定要考慮線程安全和同步。 - (v...
    幽城88閱讀 663評(píng)論 0 0
  • 一.進(jìn)程與線程 進(jìn)程是操作系統(tǒng)分配資源的最小單元囤采,線程是操作系統(tǒng)調(diào)度的最小單元述呐。一個(gè)程序至少要有進(jìn)程,一個(gè)進(jìn)程至少...
    詩(shī)酒丶趁年華閱讀 190評(píng)論 0 0