iOS中各種“鎖”的基本用法

synchronized

@synchronized(obj)指令使用的obj為該鎖的唯一標識,只有當標識相同時抛虏,才為滿足互斥匿辩,如果線程2中的@synchronized(obj)改為@synchronized(self),剛線程2就不會被阻塞。
@synchronized指令實現(xiàn)鎖的優(yōu)點就是我們不需要在代碼中顯式的創(chuàng)建鎖對象富稻,便可以實現(xiàn)鎖的機制栅盲,但作為一種預防措施汪诉,@synchronized塊會隱式的添加一個異常處理例程來保護代碼,該處理例程會在異常拋出的時候自動的釋放互斥鎖。所以如果不想讓隱式的異常處理例程帶來額外的開銷扒寄,你可以考慮使用鎖對象鱼鼓。

  • (void)synchronizedLock {
    NSObject * obj = NSObject.alloc.init;
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    @synchronized(obj) {
    NSLog(@"需要線程同步的操作1 開始");
    sleep(3);
    NSLog(@"需要線程同步的操作1 結(jié)束");
    }
    });

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    sleep(1);
    @synchronized(obj) {
    NSLog(@"需要線程同步的操作2");
    }
    });

    /**
    需要線程同步的操作1 開始
    需要線程同步的操作1 結(jié)束
    需要線程同步的操作2
    */
    }

NSLock

NSLock是Cocoa提供給我們最基本的鎖對象,這也是我們經(jīng)常所使用的该编,除lock和unlock方法外迄本,NSLock還提供了tryLock和lockBeforeDate:兩個方法,前一個方法會嘗試加鎖课竣,如果鎖不可用(已經(jīng)被鎖住)嘉赎,剛并不會阻塞線程,并返回NO于樟。lockBeforeDate:方法會在所指定Date之前嘗試加鎖曹阔,如果在指定時間之前都不能加鎖,則返回NO隔披。

  • (void)nslockLock {
    NSLock * lock = NSLock.alloc.init;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // [lock lock];
    [lock lockBeforeDate:NSDate.date];
    NSLog(@"需要線程同步的操作1 開始");
    sleep(2);
    NSLog(@"需要線程同步的操作1 結(jié)束");
    [lock unlock];
    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(1);
    if (lock.tryLock) { //嘗試獲取鎖赃份,如果獲取不到返回NO,不會阻塞
    NSLog(@"未上鎖");
    [lock unlock];
    }else {
    NSLog(@"已被上鎖");
    }

      NSDate *date = [NSDate.alloc initWithTimeIntervalSinceNow:3];
      if ([lock lockBeforeDate:date]) {
          NSLog(@"沒有超時,獲得鎖");
          [lock unlock];
      }
      else {
          NSLog(@"超時奢米,沒有獲得鎖");
      }
    

    });

    /**
    需要線程同步的操作1 開始
    已被上鎖
    需要線程同步的操作1 結(jié)束
    沒有超時抓韩,獲得鎖
    */
    }

semaphore

如果dsema信號量的值大于0,該函數(shù)所處線程就繼續(xù)執(zhí)行下面的語句鬓长,并且將信號量的值減1谒拴;如果desema的值為0,那么這個函數(shù)就阻塞當前線程等待timeout(注意timeout的類型為dispatch_time_t涉波,不能直接傳入整形或float型數(shù))英上,如果等待的期間desema的值被dispatch_semaphore_signal函數(shù)加1了,且該函數(shù)(即dispatch_semaphore_wait)所處線程獲得了信號量啤覆,那么就繼續(xù)向下執(zhí)行并將信號量減1苍日。如果等待期間沒有獲取到信號量或者信號量的值一直為0,那么等到timeout時窗声,其所處線程自動執(zhí)行其后語句相恃。
dispatch_semaphore 是信號量,但當信號總量設(shè)為 1 時也可以當作鎖來笨觅。在沒有等待情況出現(xiàn)時拦耐,它的性能比 pthread_mutex還要高,但一旦有等待情況出現(xiàn)時见剩,性能就會下降許多杀糯。相對于 OSSpinLock 來說,它的優(yōu)勢在于等待時不會消耗 CPU 資源苍苞。

  • (void)semaphoreLock {
    dispatch_semaphore_t signal = dispatch_semaphore_create(1); //初始信號量為1
    dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC); //鎖幾秒

    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    dispatch_semaphore_wait(signal, overTime); //信號量減1
    NSLog(@"需要線程同步的操作1 開始");
    sleep(2);
    NSLog(@"需要線程同步的操作1 結(jié)束");
    dispatch_semaphore_signal(signal); //信號量加1
    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(1);
    dispatch_semaphore_wait(signal, overTime);
    dispatch_semaphore_signal(signal);
    });

    /**
    需要線程同步的操作1 開始
    需要線程同步的操作1 結(jié)束
    需要線程同步的操作2

    如果超時時間overTime設(shè)置成>2固翰,可完成同步操作。如果overTime<2的話,在線程1還沒有執(zhí)行完成的情況下倦挂,此時超時了,將自動執(zhí)行下面的代碼担巩。
    需要線程同步的操作1 開始
    需要線程同步的操作2
    需要線程同步的操作1 結(jié)束
    */
    }

NSRecursiveLock 遞歸鎖

NSRecursiveLock是一個遞歸鎖方援,這個鎖可以被同一線程多次請求,而不會引起死鎖涛癌。這主要是用在循環(huán)或遞歸操作中犯戏。
這段代碼是一個典型的死鎖情況。在我們的線程中拳话,RecursiveMethod是遞歸調(diào)用的先匪。所以每次進入這個block時,都會去加一次鎖弃衍,而從第二次開始呀非,由于鎖已經(jīng)被使用了且沒有解鎖,所以它需要等待鎖被解除镜盯,這樣就導致了死鎖岸裙,線程被阻塞住了。
使用NSRecursiveLock速缆。它可以允許同一線程多次加鎖降允,而不會造成死鎖。遞歸鎖會跟蹤它被lock的次數(shù)艺糜。每次成功的lock都必須平衡調(diào)用unlock操作剧董。只有所有達到這種平衡,鎖最后才能被釋放破停,以供其它線程使用翅楼。

  • (void)recursiveLock {
    // NSLock * lock = NSLock.alloc.init; //使用nslock會產(chǎn)生死鎖
    NSRecursiveLock * lock = NSRecursiveLock.alloc.init;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    static void (^RecursiveMethod)(int);

      RecursiveMethod = ^(int value) {
          [lock lock];
          if (value > 0) {
              NSLog(@"value = %@",@(value));
              sleep(1);
              RecursiveMethod(value - 1);
          }
          [lock unlock];
      };
      
      RecursiveMethod(6);
    

    });

    /**
    value = 6
    value = 5
    value = 4
    value = 3
    value = 2
    value = 1
    */
    }

NSConditionLock 條件鎖

  • (void)lockWhenCondition:(NSInteger)condition;
  • (void)unlockWithCondition:(NSInteger)condition;
    這兩個condition一樣的時候會相互通知。

初始化 self.condition = [[NSConditionLock alloc]initWithCondition:0];
獲得鎖 [self.condition lockWhenCondition:1];
解鎖 [self.condition unlockWithCondition:1];

  • (void)conditionLockLock {
    NSConditionLock * lock = [NSConditionLock.alloc initWithCondition:0];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    while (YES) {
    [lock lockWhenCondition:1];
    NSLog(@"需要線程同步的操作1 開始");
    sleep(2);
    NSLog(@"需要線程同步的操作1 結(jié)束");
    [lock unlockWithCondition:0];
    }
    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    while (YES) {
    [lock lockWhenCondition:0];
    NSLog(@"需要線程同步的操作2 開始");
    sleep(1);
    NSLog(@"需要線程同步的操作2 結(jié)束");
    [lock unlockWithCondition:2];
    }
    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    while (YES) {
    [lock lockWhenCondition:2];
    NSLog(@"需要線程同步的操作3 開始");
    sleep(1);
    NSLog(@"需要線程同步的操作3 結(jié)束");
    [lock unlockWithCondition:1];
    }
    });

    /**
    需要線程同步的操作2 開始
    需要線程同步的操作2 結(jié)束
    需要線程同步的操作3 開始
    需要線程同步的操作3 結(jié)束
    需要線程同步的操作1 開始
    需要線程同步的操作1 結(jié)束
    */
    }

NSContidion

一種最基本的條件鎖真慢。手動控制線程wait和signal犁嗅。
[condition lock];一般用于多線程同時訪問、修改同一個數(shù)據(jù)源晤碘,保證在同一時間內(nèi)數(shù)據(jù)源只被訪問褂微、修改一次,其他線程的命令需要在lock 外等待园爷,只到unlock 宠蚂,才可訪問
[condition unlock];與lock 同時使用
[condition wait];讓當前線程處于等待狀態(tài)
[condition signal];CPU發(fā)信號告訴線程不用在等待,可以繼續(xù)執(zhí)行

  • (void)contidionLock {
    NSCondition * condition = NSCondition.alloc.init;
    NSMutableArray * products = NSMutableArray.array;

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    while (YES) {
    [condition lock];
    if (products.count == 0) {
    NSLog(@"wait for product");
    [condition wait];
    }
    [products removeObjectAtIndex:0];
    NSLog(@"custome a product");
    [condition unlock];
    }
    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    while (YES) {
    [condition lock];
    [products addObject:NSObject.alloc.init];
    NSLog(@"produce a product童社,總量:%ld",products.count);
    [condition signal];
    [condition unlock];
    sleep(2);
    }
    });

    /**
    wait for product
    produce a product求厕,總量:1
    custome a product

    wait for product
    produce a product,總量:1
    custome a product
    */
    }#pthread_mutex
    c語言定義下多線程加鎖方式。

pthread_mutex_init(pthread_mutex_t * mutex,const pthread_mutexattr_t attr);
初始化鎖變量mutex呀癣。attr為鎖屬性美浦,NULL值為默認屬性。
pthread_mutex_lock(pthread_mutex_t mutex);加鎖
pthread_mutex_tylock(pthread_mutex_t mutex);
加鎖项栏,但是與2不一樣的是當鎖已經(jīng)在使用的時候浦辨,返回為EBUSY,而不是掛起等待沼沈。
pthread_mutex_unlock(pthread_mutex_t mutex);*釋放鎖
pthread_mutex_destroy(pthread_mutex_t mutex);使用完后釋放

  • (void)pthread_mutexLock {
    __block pthread_mutex_t theLock ;
    pthread_mutex_init(&theLock, NULL);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    pthread_mutex_lock(&theLock);
    NSLog(@"需要線程同步的操作1 開始");
    sleep(3);
    NSLog(@"需要線程同步的操作1 結(jié)束");
    pthread_mutex_unlock(&theLock);

    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    sleep(1);
    pthread_mutex_lock(&theLock);
    NSLog(@"需要線程同步的操作2");
    pthread_mutex_unlock(&theLock);
    });

    /**
    需要線程同步的操作1 開始
    需要線程同步的操作1 結(jié)束
    需要線程同步的操作2
    */
    }

pthread_mutex(recursive) 遞歸鎖

這是pthread_mutex為了防止在遞歸的情況下出現(xiàn)死鎖而出現(xiàn)的遞歸鎖流酬。作用和NSRecursiveLock遞歸鎖類似。
如果使用pthread_mutex_init(&theLock, NULL);初始化鎖的話列另,上面的代碼會出現(xiàn)死鎖現(xiàn)象芽腾。如果使用遞歸鎖的形式,則沒有問題页衙。
PTHREAD_MUTEX_NORMAL 缺省類型摊滔,也就是普通鎖。當一個線程加鎖以后店乐,其余請求鎖的線程將形成一個等待隊列惭载,并在解鎖后先進先出原則獲得鎖。
PTHREAD_MUTEX_ERRORCHECK 檢錯鎖响巢,如果同一個線程請求同一個鎖描滔,則返回 EDEADLK,否則與普通鎖類型動作相同踪古。這樣就保證當不允許多次加鎖時不會出現(xiàn)嵌套情況下的死鎖含长。
PTHREAD_MUTEX_RECURSIVE 遞歸鎖,允許同一個線程對同一個鎖成功獲得多次伏穆,并通過多次 unlock 解鎖拘泞。
PTHREAD_MUTEX_DEFAULT 適應鎖,動作最簡單的鎖類型枕扫,僅等待解鎖后重新競爭陪腌,沒有等待隊列。

  • (void)pthread_mutexrecursiveLock {
    __block pthread_mutex_t theLock;

    pthread_mutexattr_t attr;
    pthread_mutexattr_init(&attr);
    pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); //設(shè)置type未遞歸
    pthread_mutex_init(&theLock, &attr);
    pthread_mutexattr_destroy(&attr);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    static void (^RecursiveMethod)(int);

      RecursiveMethod = ^(int value) {
          pthread_mutex_lock(&theLock);
          if (value > 0) {
              NSLog(@"value = %@",@(value));
              sleep(1);
              RecursiveMethod(value - 1);
          }
          pthread_mutex_unlock(&theLock);
      };
      
      RecursiveMethod(5);
    

    });

    /**
    value = 5
    value = 4
    value = 3
    value = 2
    value = 1
    */
    }

OSSpinLock OSSpinLock 自旋鎖烟瞧,性能最高的鎖诗鸭。原理很簡單,就是一直 do while 忙等参滴。它的缺點是當?shù)却龝r會消耗大量 CPU 資源强岸,所以它不適用于較長時間的任務(wù)。 不過最近YY大神在自己的博客不再安全的 OSSpinLock中說明了OSSpinLock已經(jīng)不再安全砾赔,請大家謹慎使用蝌箍。 青灼。

  • (void)osspinLock {
    _block OSSpinLock theLock = OS_SPINLOCK_INIT;
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    OSSpinLockLock(&theLock);
    NSLog(@"需要線程同步的操作1 開始");
    sleep(3);
    NSLog(@"需要線程同步的操作1 結(jié)束");
    OSSpinLockUnlock(&theLock);

    });

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    OSSpinLockLock(&theLock);
    sleep(1);
    NSLog(@"需要線程同步的操作2");
    OSSpinLockUnlock(&theLock);

    });
    }

效率對比如下:

l
來源:本文來自第三方轉(zhuǎn)載,如有侵權(quán)請聯(lián)系小編刪除妓盲。
給大家推薦一個iOS技術(shù)交流群杂拨,群內(nèi)提供數(shù)據(jù)結(jié)構(gòu)與算法、底層進階悯衬、swift弹沽、逆向、底層面試題整合文檔等免費資料I跬ぁ4摇击胜!
可加我QQ3140276761邀請大家進群亏狰。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市偶摔,隨后出現(xiàn)的幾起案子暇唾,更是在濱河造成了極大的恐慌,老刑警劉巖辰斋,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件策州,死亡現(xiàn)場離奇詭異,居然都是意外死亡宫仗,警方通過查閱死者的電腦和手機够挂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來藕夫,“玉大人孽糖,你說我怎么就攤上這事∫阒” “怎么了办悟?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長滩褥。 經(jīng)常有香客問我病蛉,道長,這世上最難降的妖魔是什么瑰煎? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任铺然,我火速辦了婚禮,結(jié)果婚禮上酒甸,老公的妹妹穿的比我還像新娘探熔。我一直安慰自己,他們只是感情好烘挫,可當我...
    茶點故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布诀艰。 她就那樣靜靜地躺著柬甥,像睡著了一般。 火紅的嫁衣襯著肌膚如雪其垄。 梳的紋絲不亂的頭發(fā)上苛蒲,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機與錄音绿满,去河邊找鬼臂外。 笑死,一個胖子當著我的面吹牛喇颁,可吹牛的內(nèi)容都是我干的漏健。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼橘霎,長吁一口氣:“原來是場噩夢啊……” “哼蔫浆!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姐叁,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤瓦盛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后外潜,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體原环,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年处窥,在試婚紗的時候發(fā)現(xiàn)自己被綠了嘱吗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,094評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡滔驾,死狀恐怖谒麦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情嵌灰,我是刑警寧澤弄匕,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站沽瞭,受9級特大地震影響迁匠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜驹溃,卻給世界環(huán)境...
    茶點故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一城丧、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧豌鹤,春花似錦亡哄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽愿卸。三九已至,卻和暖如春截型,著一層夾襖步出監(jiān)牢的瞬間趴荸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工宦焦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留发钝,地道東北人。 一個月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓波闹,卻偏偏與公主長得像酝豪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子精堕,可洞房花燭夜當晚...
    茶點故事閱讀 42,828評論 2 345

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

  • 鎖是一種同步機制孵淘,用于多線程環(huán)境中對資源訪問的限制iOS中常見鎖的性能對比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,507評論 0 6
  • (轉(zhuǎn)載) iOS 各種鎖機制 一、前言 前段時間看了幾個開源項目锄码,發(fā)現(xiàn)他們保持線程同步的方式各不相同夺英,有@syn...
    北漂老張閱讀 445評論 0 1
  • 一晌涕、前言 前段時間看了幾個開源項目滋捶,發(fā)現(xiàn)他們保持線程同步的方式各不相同,有@synchronized余黎、NSLock...
    稻春閱讀 464評論 0 0
  • 1. iOS中的互斥鎖 在編程中重窟,引入對象互斥鎖的概念,來保證共享數(shù)據(jù)操作的完整性惧财。每個對象都對應于一個可稱為“互...
    歡博閱讀 901評論 0 1
  • 今天是2019年2月5日巡扇,星期一,天氣晴垮衷。 今天是正月初一厅翔,2019年的第一天。 2019年搀突。我對之沖滿了希望刀闷。希...
    果果_bf92閱讀 185評論 0 0