一般情況下猎唁,我們定義屬性的時(shí)候都是這樣定義的:
@property (nonatomic, copy) NSString *string1;
@property (nonatomic, strong) NSMutableString *string2;
copy
和strong
的區(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ō):我們引入鎖的目的是為了線程安全怠噪。
找到一張關(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系列鎖指的是NSLock
、NSCondition
缰儿、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è)試的線程鎖的性能如下:
推薦文章(排名不分先后):
(ibireme大神的不再安全的 OSSpinLock)
http://www.reibang.com/p/1e59f0970bf5
關(guān)于遞歸鎖與非遞歸鎖联喘,平常接觸比較少华蜒,有興趣的童鞋可以了解一下:https://blog.csdn.net/zouxinfox/article/details/5838861