前言
線程安全是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)系作者