線程安全---鎖

前言

線程安全是IOS開發(fā)中避免不了的話題,隨著多線程的使用,對于資源的競爭以及數(shù)據(jù)的操作都可能存在風(fēng)險(xiǎn),所以有必要在操作時(shí)保證線程安全。線程安全是多線程技術(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ù),提高效率,單是隨之而來的也會(huì)出現(xiàn)一些由多線程使用而造成的問題。鎖主要分為:互斥鎖,遞歸鎖,信號量,條件鎖 等... 鎖的功能就是為了防止不同線程同時(shí)訪問一段代碼。下面舉個(gè)簡單的例子。
創(chuàng)建一個(gè)Pesson類 其中有一個(gè)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)槭遣煌木€程,所以不確定哪一個(gè)會(huì)先執(zhí)行結(jié)束。相信有一定基礎(chǔ)的同學(xué)都會(huì)明白其原因。因?yàn)樵谠撎幏椒ㄖ袥]有加鎖,導(dǎo)致不同線程競爭資源。當(dāng)a線程和b線程同時(shí)拿到age時(shí),例如此時(shí)的age的值是100 執(zhí)行自增之后 a線程和b線程都將101賦值給了age,但總得有個(gè)先來后到,結(jié)果就是某一次被覆蓋了。多次這樣的操作就會(huì)導(dǎo)致誤差。這個(gè)時(shí)候在多線程訪問同一資源時(shí)要通過鎖來保證同一時(shí)間僅有一個(gè)線程對該資源訪問,這樣就可以避免上述問題的發(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);
      }];
}

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

3. pthread 的全稱是POSIX thread 是一套跨平臺的多線程API,各個(gè)平臺對其都有實(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ù)會(huì)補(bǔ)充!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容