参考链接:iOS多线程中的几种加锁类型OSSpinLock、os_unfair_lock、pthread_mutex
1、pthread_mutex是c语言实现的跨平台互斥锁,应该是一种主流锁吧,OC多种形态的锁都是基于pthread_mutex,常见的有NSLock、NSCondition、NSConditionLock、NSRecursiveLock、@Synchronized
2、各种锁的基本使用
2.1、NSLock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #import "ViewController.h" #import <pthread .h> @interface ViewController () { NSLock *_lock; } @end @implementation ViewController static NSUInteger ticketCount = 20; - (void)viewDidLoad { [super viewDidLoad]; _lock = [[NSLock alloc] init]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ for (int i = 0; i < 5; i++) { [self saleTickte]; } }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ for (int i = 0; i < 5; i++) { [self saleTickte]; } }); } - (void)saleTickte { [_lock lock]; // lockBeforeDate:方法能在指定时间后自动解锁 // [_lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:3]]; NSUInteger remain = ticketCount; sleep(0.5); ticketCount = --remain; NSLog(@"%ld-%@", ticketCount, [NSThread currentThread]); [_lock unlock]; } @end |
输出结果:
2018-11-27 16:38:35.510970+0800 MultiThread[5033:2888041] 19-<NSThread: 0x600001ded000>{number = 3, name = (null)} 2018-11-27 16:38:35.511540+0800 MultiThread[5033:2888038] 18-<NSThread: 0x600001de0780>{number = 4, name = (null)} 2018-11-27 16:38:35.512453+0800 MultiThread[5033:2888038] 17-<NSThread: 0x600001de0780>{number = 4, name = (null)} 2018-11-27 16:38:35.513072+0800 MultiThread[5033:2888038] 16-<NSThread: 0x600001de0780>{number = 4, name = (null)} 2018-11-27 16:38:35.513250+0800 MultiThread[5033:2888041] 15-<NSThread: 0x600001ded000>{number = 3, name = (null)} 2018-11-27 16:38:35.513405+0800 MultiThread[5033:2888041] 14-<NSThread: 0x600001ded000>{number = 3, name = (null)} 2018-11-27 16:38:35.513543+0800 MultiThread[5033:2888041] 13-<NSThread: 0x600001ded000>{number = 3, name = (null)} 2018-11-27 16:38:35.513699+0800 MultiThread[5033:2888041] 12-<NSThread: 0x600001ded000>{number = 3, name = (null)} 2018-11-27 16:38:35.513880+0800 MultiThread[5033:2888038] 11-<NSThread: 0x600001de0780>{number = 4, name = (null)} 2018-11-27 16:38:35.514671+0800 MultiThread[5033:2888038] 10-<NSThread: 0x600001de0780>{number = 4, name = (null)} |
PS:使用pthread_mutex加锁演示上述代码结果是某个线程先加锁,似乎当前线程循环结束后才会有其他线程来抢占;但NSLock的结果即是for循环随机交替进行的。
2.2、NSCondition
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | #import "ViewController.h" #import <pthread.h> @interface ViewController () { NSCondition *_condition; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _condition = [[NSCondition alloc] init]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self methodOne]; }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self methodTwo]; }); } - (void)methodOne { [_condition lock]; [_condition wait]; // waitUntilDate:方法在等待时间之后被主动唤醒 // [_condition waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]]; NSLog(@"one, %@", [NSThread currentThread]); [_condition unlock]; } - (void)methodTwo { // 休眠0.5秒是为了让其他线程先抢占加锁 sleep(0.5); [_condition lock]; NSLog(@"two, %@", [NSThread currentThread]); [_condition signal]; [_condition unlock]; } @end |
执行结果:
2018-11-27 16:46:13.041122+0800 MultiThread[5168:2952222] two, <NSThread: 0x60000348a200>{number = 3, name = (null)} 2018-11-27 16:46:13.043408+0800 MultiThread[5168:2952220] one, <NSThread: 0x600003493100>{number = 4, name = (null)} |
2.3、NSConditionLock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | #import "ViewController.h" #import <pthread.h> @interface ViewController () { NSConditionLock *_conditionLock; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _conditionLock = [[NSConditionLock alloc] initWithCondition:0]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self methodOne]; }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self methodTwo]; }); } - (void)methodOne { [_conditionLock lockWhenCondition:0]; // lock方法等价于lockWhenCondition:0 // [_conditionLock lock]; // lockBeforeDate:、lockWhenCondition:beforeDate:方法同理 // [_conditionLock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:3]]; // [_conditionLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:3]]; NSLog(@"one, %@", [NSThread currentThread]); sleep(1); // 解锁当前锁,并发送condition信号给其他条件锁 [_conditionLock unlockWithCondition:1]; } - (void)methodTwo { // 在接收到conditon之前处于休眠状态 // lockWhenCondiont:beforeDate:方法可以避免死锁 [_conditionLock lockWhenCondition:1]; NSLog(@"two, %@", [NSThread currentThread]); [_conditionLock unlockWithCondition:1]; } @end |
运行结果:
2018-11-27 16:59:42.482479+0800 MultiThread[5378:3062761] one, <NSThread: 0x60000009a140>{number = 3, name = (null)} 2018-11-27 16:59:43.484827+0800 MultiThread[5378:3062762] two, <NSThread: 0x60000009ac40>{number = 4, name = (null)} |
2.4、NSRecursiveLock
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | #import "ViewController.h" #import <pthread.h> @interface ViewController () { NSRecursiveLock *_recursiveLock; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // 等价于pthread_mutexattr设置type PTHREAD_MUTEX_RECURSIVE _recursiveLock = [[NSRecursiveLock alloc] init]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self recursiveMethod]; }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self recursiveMethod]; }); } - (void)recursiveMethod { static int i = 0; [_recursiveLock lock]; if (i < 5) { i++; sleep(1);// 休眠1秒可以看出,当前线程占用锁后,其他线程无法再次加锁,但当前线程可以 NSLog(@"%d, %@", i, [NSThread currentThread]); [self recursiveMethod]; } [_recursiveLock unlock]; i = 0; } @end |
运行结果:
2018-11-27 17:08:30.437419+0800 MultiThread[5575:3146772] 1, <NSThread: 0x60000246f940>{number = 3, name = (null)} 2018-11-27 17:08:31.441390+0800 MultiThread[5575:3146772] 2, <NSThread: 0x60000246f940>{number = 3, name = (null)} 2018-11-27 17:08:32.444975+0800 MultiThread[5575:3146772] 3, <NSThread: 0x60000246f940>{number = 3, name = (null)} 2018-11-27 17:08:33.448204+0800 MultiThread[5575:3146772] 4, <NSThread: 0x60000246f940>{number = 3, name = (null)} 2018-11-27 17:08:34.451139+0800 MultiThread[5575:3146772] 5, <NSThread: 0x60000246f940>{number = 3, name = (null)} 2018-11-27 17:08:35.454776+0800 MultiThread[5575:3146773] 1, <NSThread: 0x600002474000>{number = 4, name = (null)} 2018-11-27 17:08:36.459969+0800 MultiThread[5575:3146773] 2, <NSThread: 0x600002474000>{number = 4, name = (null)} 2018-11-27 17:08:37.462625+0800 MultiThread[5575:3146773] 3, <NSThread: 0x600002474000>{number = 4, name = (null)} 2018-11-27 17:08:38.466880+0800 MultiThread[5575:3146773] 4, <NSThread: 0x600002474000>{number = 4, name = (null)} 2018-11-27 17:08:39.472285+0800 MultiThread[5575:3146773] 5, <NSThread: 0x600002474000>{number = 4, name = (null)} |
2.5、@synchronized(token){}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | #import "ViewController.h" #import <pthread.h> @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self methodOne]; }); dispatch_async(dispatch_get_global_queue(0, 0), ^{ [self methodTwo]; }); } - (void)methodOne { // token相同即为同一锁,大括号开始为加锁,结果为解锁,使用简单但效率不高 @synchronized (self) { NSLog(@"one, %@", [NSThread currentThread]); sleep(1); } } - (void)methodTwo { @synchronized (self) { NSLog(@"two, %@", [NSThread currentThread]); } } @end |
执行结果:
2018-11-27 17:15:02.233273+0800 MultiThread[5688:3202460] one, <NSThread: 0x60000312d780>{number = 3, name = (null)} 2018-11-27 17:15:03.237778+0800 MultiThread[5688:3202462] two, <NSThread: 0x60000312ec80>{number = 4, name = (null)} |
iOS线程同步方案性能比较:
os_unfair_lock > OSSpinLock > dispatch_semaphore > pthread_mutex > dispatch_queue > NSLock > NSCondition > pthread_mutex(recursive) > NSRecursiveLock > NSConditionLock > @Synchronized