iOS開發(fā)-iOS中的八種鎖

在iOS開發(fā)中,經(jīng)常會(huì)用到多線程開發(fā)的情況,這時(shí)候如果多個(gè)線程同時(shí)訪問(wèn)同一塊資源時(shí),就很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全的問(wèn)題,這個(gè)時(shí)候我們就需要有一個(gè)方法來(lái)保證每次只有一個(gè)線程訪問(wèn)這一塊資源,這個(gè)方法就是。

iOS中一共有8中常用的鎖,我們用YY大神的一張圖來(lái)看一下這些鎖的性能。

lcok.png

OSSpinLock 自旋鎖

OSSpinLock 自旋鎖在圖表中可以看到,性能是最高的,大概在150us,但是YY大神在不再安全的 OSSpinLock中說(shuō)道OSSpinLock自旋鎖已經(jīng)不再安全了。

而且也可以看到OSSpinLock已經(jīng)在iOS 10.0之后廢棄了。

lock_OSSpinLock.png

好了,接下來(lái)看一下OSSpinLock中的方法。

  • OS_SPINLOCK_INIT: 默認(rèn)值為 0,在 locked 狀態(tài)時(shí)就會(huì)大于 0,unlocked狀態(tài)下為 0

  • OSSpinLockLock(&oslock):上鎖,參數(shù)為 OSSpinLock 地址

  • OSSpinLockUnlock(&oslock):解鎖,參數(shù)為 OSSpinLock 地址

  • OSSpinLockTry(&oslock):嘗試加鎖,可以加鎖則立即加鎖并返回 YES,反之返回 NO

接下來(lái)我們測(cè)試一下,比如下面一段代碼中,我們開啟兩個(gè)異步線程。


- (void)setOSSpinLock

{

 __block OSSpinLock ossPinLock = OS_SPINLOCK_INIT;

 __block NSInteger number = 10;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 10;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 20;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 });

}

可以看到打印出來(lái)的數(shù)據(jù)都是錯(cuò)亂的:


2018-04-23 16:33:12.655341+0800 LockDemo[88725:6234113] 當(dāng)前線程:<NSThread: 0x604000270d00>{number = 3, name = (null)},number=10

2018-04-23 16:33:12.655341+0800 LockDemo[88725:6234116] 當(dāng)前線程:<NSThread: 0x60000026f340>{number = 4, name = (null)},number=10

2018-04-23 16:33:12.655651+0800 LockDemo[88725:6234116] 當(dāng)前線程:<NSThread: 0x60000026f340>{number = 4, name = (null)},number=40

2018-04-23 16:33:12.655655+0800 LockDemo[88725:6234113] 當(dāng)前線程:<NSThread: 0x604000270d00>{number = 3, name = (null)},number=40

這時(shí)候,我們添加一下上OSSpinLock自旋鎖:

首先引入OSSpinLock自旋鎖的庫(kù):


#import <libkern/OSAtomic.h>


- (void)setOSSpinLock

{

 __block OSSpinLock ossPinLock = OS_SPINLOCK_INIT;

 __block NSInteger number = 10;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,OSSpinLock上鎖",[NSThread currentThread]);

 OSSpinLockLock(&ossPinLock);

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 10;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 NSLog(@"當(dāng)前線程:%@,OSSpinLock解鎖",[NSThread currentThread]);

 OSSpinLockUnlock(&ossPinLock);

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,OSSpinLock上鎖",[NSThread currentThread]);

 OSSpinLockLock(&ossPinLock);

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 20;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 NSLog(@"當(dāng)前線程:%@,OSSpinLock解鎖",[NSThread currentThread]);

 OSSpinLockUnlock(&ossPinLock);

 });

}

可以看到打印的數(shù)據(jù):


2018-04-23 16:34:40.764216+0800 LockDemo[88797:6236783] 當(dāng)前線程:<NSThread: 0x60000027dcc0>{number = 3, name = (null)},OSSpinLock上鎖

2018-04-23 16:34:40.764216+0800 LockDemo[88797:6236781] 當(dāng)前線程:<NSThread: 0x60000027da40>{number = 4, name = (null)},OSSpinLock上鎖

2018-04-23 16:34:40.764450+0800 LockDemo[88797:6236783] 當(dāng)前線程:<NSThread: 0x60000027dcc0>{number = 3, name = (null)},number=10

2018-04-23 16:34:40.764577+0800 LockDemo[88797:6236783] 當(dāng)前線程:<NSThread: 0x60000027dcc0>{number = 3, name = (null)},number=20

2018-04-23 16:34:40.764736+0800 LockDemo[88797:6236783] 當(dāng)前線程:<NSThread: 0x60000027dcc0>{number = 3, name = (null)},OSSpinLock解鎖

2018-04-23 16:34:40.766647+0800 LockDemo[88797:6236781] 當(dāng)前線程:<NSThread: 0x60000027da40>{number = 4, name = (null)},number=20

2018-04-23 16:34:40.766910+0800 LockDemo[88797:6236781] 當(dāng)前線程:<NSThread: 0x60000027da40>{number = 4, name = (null)},number=40

2018-04-23 16:34:40.768117+0800 LockDemo[88797:6236781] 當(dāng)前線程:<NSThread: 0x60000027da40>{number = 4, name = (null)},OSSpinLock解鎖

dispatch_semaphore 信號(hào)量

信號(hào)量是僅次于自旋鎖的方法,使用的是GCD提供的API:

  • dispatch_semaphore_create 創(chuàng)建一個(gè)Semphore并初始化信號(hào)的總量。

  • dispatch_semaphore_signal 發(fā)送一個(gè)信號(hào),讓信號(hào)總量加1。

  • dispatch_semaphore_wait 可以使總信號(hào)量減1,讓信號(hào)總量為0時(shí)就會(huì)一直等待,否則就可以正常執(zhí)行。

這次我們就不上測(cè)試的代碼了,直接放上增加信號(hào)量的代碼:


- (void)setSemaphore

{

 dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);

 dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3.0f * NSEC_PER_SEC);

 __block NSInteger number = 10;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,semaphore信號(hào)量+1",[NSThread currentThread]);

 dispatch_semaphore_signal(semaphore);

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 10;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 NSLog(@"當(dāng)前線程:%@,semaphore信號(hào)量-1",[NSThread currentThread]);

 dispatch_semaphore_wait(semaphore, overTime);

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,semaphore信號(hào)量+1",[NSThread currentThread]);

 dispatch_semaphore_signal(semaphore);

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 20;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 NSLog(@"當(dāng)前線程:%@,semaphore信號(hào)量-1",[NSThread currentThread]);

 dispatch_semaphore_wait(semaphore, overTime);

 });

}

打印結(jié)果:


2018-04-23 17:05:22.368340+0800 LockDemo[89577:6266694] 當(dāng)前線程:<NSThread: 0x60000026ed00>{number = 3, name = (null)},semaphore信號(hào)量+1

2018-04-23 17:05:22.368340+0800 LockDemo[89577:6266693] 當(dāng)前線程:<NSThread: 0x60000026ed80>{number = 4, name = (null)},semaphore信號(hào)量+1

2018-04-23 17:05:22.368625+0800 LockDemo[89577:6266694] 當(dāng)前線程:<NSThread: 0x60000026ed00>{number = 3, name = (null)},number=10

2018-04-23 17:05:22.368630+0800 LockDemo[89577:6266693] 當(dāng)前線程:<NSThread: 0x60000026ed80>{number = 4, name = (null)},number=10

2018-04-23 17:05:22.368763+0800 LockDemo[89577:6266694] 當(dāng)前線程:<NSThread: 0x60000026ed00>{number = 3, name = (null)},number=20

2018-04-23 17:05:22.368888+0800 LockDemo[89577:6266694] 當(dāng)前線程:<NSThread: 0x60000026ed00>{number = 3, name = (null)},semaphore信號(hào)量-1

2018-04-23 17:05:22.368887+0800 LockDemo[89577:6266693] 當(dāng)前線程:<NSThread: 0x60000026ed80>{number = 4, name = (null)},number=40

2018-04-23 17:05:22.369799+0800 LockDemo[89577:6266693] 當(dāng)前線程:<NSThread: 0x60000026ed80>{number = 4, name = (null)},semaphore信號(hào)量-1

pthread_mutex 互斥鎖

YY大神在之前的文章中已經(jīng)說(shuō)過(guò)OSSpinLock已經(jīng)不再是線程安全的并把自己開源項(xiàng)目中的OSSpinLock都換成了pthread_mutex。

接下來(lái)我們看一下互斥鎖提供的方法:

  • pthread_mutex_init(&pLock, NULL);:參數(shù)為 pthread_mutex 地址,第二個(gè)參數(shù)默認(rèn)PTHREAD_MUTEX_NORMAL

  • pthread_mutex_lock(&pLock):上鎖,參數(shù)為 pthread_mutex 地址

  • pthread_mutex_unlock(&pLock):解鎖,參數(shù)為 pthread_mutex 地址

  • pthread_mutex_trylock(&pLock):嘗試加鎖,可以加鎖則立即加鎖并返回 0 ,否者返回一個(gè)錯(cuò)誤提示碼。

接下來(lái)看代碼:


- (void)setPthread_mutex

{

 static pthread_mutex_t pLock;

 pthread_mutex_init(&pLock, NULL);

 __block NSInteger number = 10;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,上鎖",[NSThread currentThread]);

 pthread_mutex_lock(&pLock);

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 10;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 NSLog(@"當(dāng)前線程:%@,解鎖",[NSThread currentThread]);

 pthread_mutex_unlock(&pLock);

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,上鎖",[NSThread currentThread]);

 pthread_mutex_lock(&pLock);

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 20;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 NSLog(@"當(dāng)前線程:%@,解鎖",[NSThread currentThread]);

 pthread_mutex_unlock(&pLock);

 });

}

然后是打印結(jié)果:


2018-04-23 17:13:09.376128+0800 LockDemo[89821:6278824] 當(dāng)前線程:<NSThread: 0x600000474900>{number = 3, name = (null)},上鎖

2018-04-23 17:13:09.376128+0800 LockDemo[89821:6278825] 當(dāng)前線程:<NSThread: 0x6000004744c0>{number = 4, name = (null)},上鎖

2018-04-23 17:13:09.376419+0800 LockDemo[89821:6278824] 當(dāng)前線程:<NSThread: 0x600000474900>{number = 3, name = (null)},number=10

2018-04-23 17:13:09.376547+0800 LockDemo[89821:6278824] 當(dāng)前線程:<NSThread: 0x600000474900>{number = 3, name = (null)},number=20

2018-04-23 17:13:09.376759+0800 LockDemo[89821:6278824] 當(dāng)前線程:<NSThread: 0x600000474900>{number = 3, name = (null)},解鎖

2018-04-23 17:13:09.378000+0800 LockDemo[89821:6278825] 當(dāng)前線程:<NSThread: 0x6000004744c0>{number = 4, name = (null)},number=20

2018-04-23 17:13:09.378627+0800 LockDemo[89821:6278825] 當(dāng)前線程:<NSThread: 0x6000004744c0>{number = 4, name = (null)},number=40

2018-04-23 17:13:09.378846+0800 LockDemo[89821:6278825] 當(dāng)前線程:<NSThread: 0x6000004744c0>{number = 4, name = (null)},解鎖

pthread_mutex(recursive) 遞歸鎖

遞歸鎖最大的特點(diǎn)就是允許同一個(gè)線程在未釋放其擁有的鎖時(shí)反復(fù)對(duì)該鎖進(jìn)行加鎖操作。而之前介紹的幾種鎖可以看到,加鎖后只能有一個(gè)線程訪問(wèn)該對(duì)象,后面的線程需要排隊(duì),并且lock和unlock都是對(duì)應(yīng)出現(xiàn)的。

下面是代碼:


- (void)setPthreadMutexRecursive

{

 static pthread_mutex_t pLock;

 pthread_mutexattr_t attr;

 //初始化attr并且給它賦予默認(rèn)

 pthread_mutexattr_init(&attr);

 //設(shè)置鎖類型,這邊是設(shè)置為遞歸鎖

 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);

 pthread_mutex_init(&pLock, &attr);

 //銷毀一個(gè)屬性對(duì)象,在重新進(jìn)行初始化之前該結(jié)構(gòu)不能重新使用

 pthread_mutexattr_destroy(&attr);

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 static void (^RecursiveBlock)(int);

 RecursiveBlock = ^(int value) {

 pthread_mutex_lock(&pLock);

 if (value > 0) {

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],value);

 RecursiveBlock(value - 1);

 }

 pthread_mutex_unlock(&pLock);

 };

 RecursiveBlock(5);

 });

}

打印結(jié)果:


2018-04-23 17:34:36.252635+0800 LockDemo[90381:6304880] 當(dāng)前線程:<NSThread: 0x60000046ec00>{number = 3, name = (null)},number=5

2018-04-23 17:34:36.252947+0800 LockDemo[90381:6304880] 當(dāng)前線程:<NSThread: 0x60000046ec00>{number = 3, name = (null)},number=4

2018-04-23 17:34:36.253129+0800 LockDemo[90381:6304880] 當(dāng)前線程:<NSThread: 0x60000046ec00>{number = 3, name = (null)},number=3

2018-04-23 17:34:36.254451+0800 LockDemo[90381:6304880] 當(dāng)前線程:<NSThread: 0x60000046ec00>{number = 3, name = (null)},number=2

2018-04-23 17:34:36.254692+0800 LockDemo[90381:6304880] 當(dāng)前線程:<NSThread: 0x60000046ec00>{number = 3, name = (null)},number=1

NSLock

NSLock看名字就會(huì)熟悉一些了,我們來(lái)看一下他的API:

  • lock:上鎖

  • unlock:解鎖

  • trylock:能加鎖返回 YES 并執(zhí)行加鎖操作,相當(dāng)于 lock,反之返回 NO。

  • lockBeforeDate:這個(gè)方法表示會(huì)在傳入的時(shí)間內(nèi)嘗試加鎖,若能加鎖則執(zhí)行加鎖操作并返回 YES,反之返回 NO。

接下來(lái)上代碼:


- (void)setNSLock

{

 NSLock *lock = [NSLock new];

 __block NSInteger number = 10;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,NSLock上鎖",[NSThread currentThread]);

 [lock lock];

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 10;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 NSLog(@"當(dāng)前線程:%@,NSLock解鎖",[NSThread currentThread]);

 [lock unlock];

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,NSLock上鎖",[NSThread currentThread]);

 [lock lock];

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 20;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 NSLog(@"當(dāng)前線程:%@,NSLock解鎖",[NSThread currentThread]);

 [lock unlock];

 });

}

打印結(jié)果:


2018-04-23 17:41:40.355403+0800 LockDemo[90636:6315709] 當(dāng)前線程:<NSThread: 0x604000464340>{number = 4, name = (null)},NSLock上鎖

2018-04-23 17:41:40.355403+0800 LockDemo[90636:6315707] 當(dāng)前線程:<NSThread: 0x604000464400>{number = 3, name = (null)},NSLock上鎖

2018-04-23 17:41:40.355620+0800 LockDemo[90636:6315709] 當(dāng)前線程:<NSThread: 0x604000464340>{number = 4, name = (null)},number=10

2018-04-23 17:41:40.355768+0800 LockDemo[90636:6315709] 當(dāng)前線程:<NSThread: 0x604000464340>{number = 4, name = (null)},number=30

2018-04-23 17:41:40.355913+0800 LockDemo[90636:6315709] 當(dāng)前線程:<NSThread: 0x604000464340>{number = 4, name = (null)},NSLock解鎖

2018-04-23 17:41:40.357151+0800 LockDemo[90636:6315707] 當(dāng)前線程:<NSThread: 0x604000464400>{number = 3, name = (null)},number=30

2018-04-23 17:41:40.357313+0800 LockDemo[90636:6315707] 當(dāng)前線程:<NSThread: 0x604000464400>{number = 3, name = (null)},number=40

2018-04-23 17:41:40.357522+0800 LockDemo[90636:6315707] 當(dāng)前線程:<NSThread: 0x604000464400>{number = 3, name = (null)},NSLock解鎖

NSCondition

這個(gè)方法和信號(hào)量有點(diǎn)相似:

  • wait:進(jìn)入等待狀態(tài)

  • waitUntilDate::讓一個(gè)線程等待一定的時(shí)間

  • signal:?jiǎn)拘岩粋€(gè)等待的線程

  • broadcast:?jiǎn)拘阉械却木€程

### 線程延遲執(zhí)行

上代碼:


- (void)setNSConditionUntilDate

{

 NSCondition *conditionLock = [NSCondition new];

 __block NSInteger number = 10;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,NSCondition上鎖",[NSThread currentThread]);

 [conditionLock lock];

 [conditionLock waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:3]];

 number = number + 1;

 NSLog(@"number=%ld",number);

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 [conditionLock unlock];

 });   

}

可以看到打印代碼中number=11的代碼在第一次輸出的3s之后。


2018-04-24 10:13:22.892167+0800 LockDemo[92613:6424100] 當(dāng)前線程:<NSThread: 0x600000277300>{number = 3, name = (null)},NSCondition上鎖

2018-04-24 10:13:25.895626+0800 LockDemo[92613:6424100] number=11

2018-04-24 10:13:25.896116+0800 LockDemo[92613:6424100] 當(dāng)前線程:<NSThread: 0x600000277300>{number = 3, name = (null)},number=11

喚醒等待線程

上代碼:


- (void)setNSConditionWait

{

 NSCondition *conditionLock = [NSCondition new];

 __block NSInteger number = 10;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,NSCondition上鎖",[NSThread currentThread]);

 [conditionLock lock];

 [conditionLock wait];

 number = number + 10;

 NSLog(@"number=%ld",number);

 [conditionLock unlock];

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,NSCondition上鎖",[NSThread currentThread]);

 [conditionLock lock];

 [conditionLock wait];

 number = number + 20;

 NSLog(@"number=%ld",number);

 [conditionLock unlock];

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 sleep(2);

 NSLog(@"當(dāng)前線程:%@,NSCondition喚醒等待的線程",[NSThread currentThread]);

 [conditionLock signal];

 });

}

打印結(jié)果:


2018-04-24 10:21:48.119910+0800 LockDemo[92914:6437121] 當(dāng)前線程:<NSThread: 0x604000466d00>{number = 4, name = (null)},NSCondition上鎖

2018-04-24 10:21:48.119911+0800 LockDemo[92914:6437122] 當(dāng)前線程:<NSThread: 0x604000466dc0>{number = 3, name = (null)},NSCondition上鎖

2018-04-24 10:21:50.121817+0800 LockDemo[92914:6437120] 當(dāng)前線程:<NSThread: 0x6000002764c0>{number = 5, name = (null)},NSCondition喚醒等待的線程

2018-04-24 10:21:50.122050+0800 LockDemo[92914:6437121] number=30

喚醒所有等待線程


- (void)setNSConditionBroadcast

{

 NSCondition *conditionLock = [NSCondition new];

 __block NSInteger number = 10;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,NSCondition上鎖",[NSThread currentThread]);

 [conditionLock lock];

 [conditionLock wait];

 number = number + 10;

 NSLog(@"number=%ld",number);

 [conditionLock unlock];

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 NSLog(@"當(dāng)前線程:%@,NSCondition上鎖",[NSThread currentThread]);

 [conditionLock lock];

 [conditionLock wait];

 number = number + 20;

 NSLog(@"number=%ld",number);

 [conditionLock unlock];

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 sleep(2);

 NSLog(@"當(dāng)前線程:%@,NSCondition喚醒所有等待的線程",[NSThread currentThread]);

 [conditionLock broadcast];

 });

}

打印結(jié)果:


2018-04-24 10:23:26.901406+0800 LockDemo[92991:6440383] 當(dāng)前線程:<NSThread: 0x600000277480>{number = 3, name = (null)},NSCondition上鎖

2018-04-24 10:23:26.901406+0800 LockDemo[92991:6440385] 當(dāng)前線程:<NSThread: 0x60400026d7c0>{number = 4, name = (null)},NSCondition上鎖

2018-04-24 10:23:28.904168+0800 LockDemo[92991:6440386] 當(dāng)前線程:<NSThread: 0x60400026df40>{number = 5, name = (null)},NSCondition喚醒所有等待的線程

2018-04-24 10:23:28.904544+0800 LockDemo[92991:6440383] number=20

2018-04-24 10:23:28.904763+0800 LockDemo[92991:6440385] number=40

@synchronized 條件鎖

@synchronized 應(yīng)該是一種比較簡(jiǎn)單的鎖。

直接上代碼:


- (void)setSynchronized

{

 __block NSInteger number = 10;

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 @synchronized (self)

 {

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 10;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 }

 });

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 @synchronized (self)

 {

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 number += 20;

 NSLog(@"當(dāng)前線程:%@,number=%ld",[NSThread currentThread],number);

 }

 });

}

打印結(jié)果:


2018-04-24 10:29:48.814631+0800 LockDemo[93300:6451071] 當(dāng)前線程:<NSThread: 0x600000467900>{number = 3, name = (null)},number=10

2018-04-24 10:29:48.815056+0800 LockDemo[93300:6451071] 當(dāng)前線程:<NSThread: 0x600000467900>{number = 3, name = (null)},number=20

2018-04-24 10:29:48.815291+0800 LockDemo[93300:6451070] 當(dāng)前線程:<NSThread: 0x600000468000>{number = 4, name = (null)},number=20

2018-04-24 10:29:48.816572+0800 LockDemo[93300:6451070] 當(dāng)前線程:<NSThread: 0x600000468000>{number = 4, name = (null)},number=40

NSConditionLock 條件鎖

這個(gè)鎖和NSLock相差不大,多了一個(gè)condition參數(shù),可以理解為一個(gè)條件標(biāo)示。也可以實(shí)現(xiàn)任務(wù)之前的互相依賴。

放代碼:


- (void)setConditionLock

{

 NSConditionLock *condationLock = [[NSConditionLock alloc] init];

 //線程1

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 if([condationLock tryLockWhenCondition:0]){

 NSLog(@"線程1");

 [condationLock unlockWithCondition:1];

 }else{

 NSLog(@"失敗");

 }

 });

 //線程2

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 [condationLock lockWhenCondition:3];

 NSLog(@"線程2");

 [condationLock unlockWithCondition:2];

 });

 //線程3

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

 [condationLock lockWhenCondition:1];

 NSLog(@"線程3");

 [condationLock unlockWithCondition:3];

 });

}

打印結(jié)果:


2018-04-24 10:46:04.325347+0800 LockDemo[93661:6468125] 線程1

2018-04-24 10:46:04.325573+0800 LockDemo[93661:6468124] 線程3

2018-04-24 10:46:04.325775+0800 LockDemo[93661:6468122] 線程2

由上可知,我們?cè)诔跏蓟?NSConditionLock 對(duì)象時(shí),給了他的標(biāo)示為 0;執(zhí)行 tryLockWhenCondition:時(shí),我們傳入的條件標(biāo)示也是 0,所 以線程1 加鎖成功;執(zhí)行 unlockWithCondition:時(shí),這時(shí)候會(huì)把condition由 0 修改為 1;因?yàn)閏ondition 修改為了 1, 會(huì)先走到 線程3,然后 線程3 又將 condition 修改為 3,最后走了線程2 的流程。

最后

以上就是全部的內(nèi)容,還是放一個(gè)demo在這里吧。

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

相關(guān)閱讀更多精彩內(nèi)容

  • 鎖是一種同步機(jī)制,用于多線程環(huán)境中對(duì)資源訪問(wèn)的限制iOS中常見鎖的性能對(duì)比圖(摘自:ibireme): iOS鎖的...
    LiLS閱讀 1,630評(píng)論 0 6
  • 補(bǔ)充: 可以看到除了OSSpinLock外,dispatch_semaphore和pthread_mutex性能是...
    笨坨閱讀 3,646評(píng)論 0 10
  • 前言 ??在使用多線程的時(shí)候多個(gè)線程可能會(huì)訪問(wèn)同一塊資源,這樣就很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全等問(wèn)題。解決資源爭(zhēng)用,...
    小盟城主閱讀 1,474評(píng)論 0 3
  • 為什么要有鎖? 在使用多線程的時(shí)候多個(gè)線程可能會(huì)訪問(wèn)同一塊資源,這樣就很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全等問(wèn)題,這時(shí)候就...
    153037c65b0c閱讀 610評(píng)論 0 1
  • 轉(zhuǎn)自(https://bestswifter.com/ios-lock/#) 深入理解 iOS 開發(fā)中的鎖 摘要 ...
    犯色戒的和尚閱讀 378評(píng)論 0 1

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