前言
iOS-锁的原理分析(一)我们分析了synchronized锁,这篇文章我们继续介绍其它的锁。
1 锁的分类
在我们项目应用中, 除了synchronized以外,我们也使用过其它的类,比如NSLock、NSCondition、NSConditionLock、NSRecursiveLock等之类的锁,那么在我们iOS中,锁到底有几种呢?我们来看下。
其实在iOS中分为两大种锁,自旋锁,互斥锁。
互斥锁是⼀种⽤于多线程编程中,防⽌两条线程同时对同⼀公共资源(⽐如全局变量)进行读写的的机制,其目地通过将代码切片成一个一个的临界区而达成。它是一种闲等待,这里又分递归和不递归
比如像:
- NSLock
- pthread_mutex
- synchronized
⾃旋锁:线程反复检查锁变量是否可⽤。由于线程在这⼀过程中保持执⾏,因此是⼀种忙等待。⼀旦获取了⾃旋锁,线程会⼀直保持该锁,直⾄显式释放⾃旋锁。⾃旋锁避免了进程上下⽂的调度开销,因此对于线程只会阻塞很短时间的场合是有效的。
2 NSLock和NSRecursiveLock的分析
我们先来看下以下代码:
- (void)ro_crash{
NSLog(@"robert");
for (int i = 0; i < 200000; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
_testArray = [NSMutableArray array];
});
}
}
这里多线程中_testArray会出现崩溃,这里加锁处理就可以解决。
dispatch_async(dispatch_get_global_queue(0, 0), ^{
static void (^testMethod)(int);
testMethod = ^(int value){
if (value > 0) {
NSLog(@"current value = %d",value);
testMethod(value - 1);
}
};
testMethod(10);
});
我们运行一下,看下效果,如图:
这是按顺序打印出来了value值,如果我们加一个循环会如何,代码如下:
NSLock *lock = [[NSLock alloc] init];
for (int i= 0; i<10; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
static void (^testMethod)(int);
testMethod = ^(int value){
if (value > 0) {
NSLog(@"current value = %d",value);
testMethod(value - 1);
}
};
testMethod(10);
});
}
它的运行效果,如图:
这里数据出问题,这是多线程引线的线程不安全,所以这里需要加锁处理,那么这么锁加在哪里呢?我们来看下。
NSLock *lock = [[NSLock alloc] init];
for (int i= 0; i<10; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
static void (^testMethod)(int);
[lock lock];
testMethod = ^(int value){
if (value > 0) {
NSLog(@"current value = %d",value);
testMethod(value - 1);
}
};
testMethod(10);
[lock unlock];
});
}
像这样加锁可以解决,或者在
[lock lock];
testMethod(10);
[lock unlock];
也可以解决。
如果我们把代码改成以下方式:
NSLock *lock = [[NSLock alloc] init];
for (int i= 0; i<10; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
static void (^testMethod)(int);
testMethod = ^(int value){
[lock lock];
if (value > 0) {
NSLog(@"current value = %d",value);
testMethod(value - 1);
}
};
testMethod(10);
[lock unlock];
});
}
经过测试是不可以的,造成类似死锁,在testMethod中,testMethod(value - 1);这行代码会在进入testMethod中,又加锁一次,不断的递归加锁,这时候递归加锁出现的问题,这也证实了NSLock是非递归的,无法还原出来,造成了类似死锁的现象,当然我们可以通过synchronized来解决。这次我们不用它,我们用NSRecursiveLock来试下,代码如下:
self.recursiveLock = [[NSRecursiveLock alloc] init];
for (int i= 0; i<10; i++) {
dispatch_async(dispatch_get_global_queue(0, 0), ^{
static void (^testMethod)(int);
testMethod = ^(int value){
[self.recursiveLock lock];
if (value > 0) {
NSLog(@"current value = %d",value);
testMethod(value - 1);
}
};
testMethod(10);
[self.recursiveLock unlock];
});
}
其结果如图:
上图也说明了执行没有问题,说明NSRecursiveLock是递归的,但是我们有testMethod(10); 这行代码,只打印一次的输出,为什么呢,因为iOS-锁的原理分析(一)这篇文章介绍过,递归锁是无法对多线程起作用的,我们可以用synchronized这把锁解决,因为它解决了可多线程。
3 NSCondition的分析
我们先把代码放上来。
RoLock.h代码:
#import
NS_ASSUME_NONNULL_BEGIN
@interface RoLock : NSObject
@property (nonatomic, copy) NSThread *thread;
@property (nonatomic, assign) int value;
@property (nonatomic, assign) int condition;
- (void)mylockWithCondition:(int)condition;
- (void)myUnlockWithCondition:(int)condition;
@end
NS_ASSUME_NONNULL_END
RoLock.m代码:
#import "RoLock.h"
@interface RoLock ()
@property (nonatomic, strong) NSCondition *testCondition;
@end
@implementation RoLock
- (instancetype)init
{
self = [super init];
if (self) {
_testCondition = [NSCondition new];
_value = 2;
}
return self;
}
- (void)mylockWithCondition:(int)condition {
[_testCondition lock];
while (_thread != nil || _value != condition) {
if (![_testCondition waitUntilDate:[NSDate distantPast]]) {
[_testCondition unlock];
}
}
_thread = [NSThread currentThread];
[_testCondition unlock];
}
- (void)myUnlockWithCondition:(int)condition {
_value = condition;
[_testCondition lock];
_thread = nil;
[_testCondition broadcast];
[_testCondition unlock];
}
@end
ViewController.m代码:
#import "ViewController.h"
#import "RoLock.h"
@interface ViewController ()
@property (nonatomic, assign) NSUInteger ticketCount;
@property (nonatomic, strong) NSCondition *testCondition;
@property (nonatomic, strong) RoLock *myLock;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.ticketCount = 0;
self.myLock = [[RoLock alloc] init];
[self ro_testConditon];
}
#pragma mark -- NSCondition
- (void)ro_testConditon{
_testCondition = [[NSCondition alloc] init];
//创建生产-消费者
for (int i = 0; i < 50; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self ro_producer];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self ro_consumer];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self ro_consumer];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[self ro_producer];
});
}
}
- (void)ro_producer{
[_testCondition lock]; // 操作的多线程影响
self.ticketCount = self.ticketCount + 1;
NSLog(@"生产一个 现有 count %zd",self.ticketCount);
[_testCondition signal]; // 信号
[_testCondition unlock];
}
- (void)ro_consumer{
[_testCondition lock]; // 操作的多线程影响
if (self.ticketCount == 0) {
NSLog(@"等待 count %zd",self.ticketCount);
[_testCondition wait];
}
//注意消费行为,要在等待条件判断之后
self.ticketCount -= 1;
NSLog(@"消费一个 还剩 count %zd ",self.ticketCount);
[_testCondition unlock];
}
#pragma mark -- NSConditionLock
- (void)ro_testConditonLock{
/**
1: NSConditionLock VS NSCondition
2: 2 -> 是什么东西
3: lockWhenCondition -> 如何控制
4: unlockWithCondition 又做了什么?
*/
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:2];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[conditionLock lockWhenCondition:1];
NSLog(@"线程 1");
[conditionLock unlockWithCondition:0];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[conditionLock lockWhenCondition:2];
sleep(0.1);
NSLog(@"线程 2");
[conditionLock unlockWithCondition:1];
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[conditionLock lock];
NSLog(@"线程 3");
[conditionLock unlock];
});
//
}
我们接下来分析NSCondition这个锁。
NSCondition的对象实际上作为⼀个锁和⼀个线程检查器:锁主要为了当检测条件时保护数据源,执⾏条件引发的任务;线程检查器,主要是根据条件决定是否继续运⾏线程,即线程是否被阻塞。
- [condition lock]; ⼀般⽤于多线程同时访问、修改同⼀个数据源,保证在时间内数据源只被访问、修改⼀次,其他线程的命令需要在lock 外等待,只到unlock ,才可访问
- [condition unlock]; 与lock 同时使⽤
- [condition wait]; 让当前线程处于等待状态
- [condition signal]; cpu发信号告诉线程不⽤在等待,可以继续执⾏
这里我们不加锁的情况如图:
2021-08-19 12:32:31.571513+0800 004-NSCondition[61699:2558417] 等待 count 0
2021-08-19 12:32:31.571514+0800 004-NSCondition[61699:2558419] 生产一个 现有 count 1
2021-08-19 12:32:31.571537+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 0
2021-08-19 12:32:31.571514+0800 004-NSCondition[61699:2558418] 生产一个 现有 count 1
2021-08-19 12:32:31.571739+0800 004-NSCondition[61699:2558417] 消费一个 还剩 count 0
2021-08-19 12:32:31.571765+0800 004-NSCondition[61699:2558419] 生产一个 现有 count 1
2021-08-19 12:32:31.571791+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 0
2021-08-19 12:32:31.571819+0800 004-NSCondition[61699:2558418] 等待 count 0
2021-08-19 12:32:31.571867+0800 004-NSCondition[61699:2558419] 生产一个 现有 count 1
2021-08-19 12:32:31.571871+0800 004-NSCondition[61699:2558417] 生产一个 现有 count 2
2021-08-19 12:32:31.571963+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 1
2021-08-19 12:32:31.572315+0800 004-NSCondition[61699:2558420] 消费一个 还剩 count 0
2021-08-19 12:32:31.572669+0800 004-NSCondition[61699:2558416] 生产一个 现有 count 1
2021-08-19 12:32:31.572747+0800 004-NSCondition[61699:2558418] 消费一个 还剩 count 0
2021-08-19 12:32:31.574770+0800 004-NSCondition[61699:2558419] 生产一个 现有 count 1
2021-08-19 12:32:31.574952+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 0
2021-08-19 12:32:31.575127+0800 004-NSCondition[61699:2558417] 等待 count 0
2021-08-19 12:32:31.575247+0800 004-NSCondition[61699:2558420] 生产一个 现有 count 1
2021-08-19 12:32:31.575573+0800 004-NSCondition[61699:2558418] 生产一个 现有 count 2
2021-08-19 12:32:31.575933+0800 004-NSCondition[61699:2558419] 消费一个 还剩 count 1
2021-08-19 12:32:31.576146+0800 004-NSCondition[61699:2558417] 消费一个 还剩 count 0
2021-08-19 12:32:31.576446+0800 004-NSCondition[61699:2558416] 等待 count 0
2021-08-19 12:32:31.576768+0800 004-NSCondit2021-08-19 12:32:31.576974+0800 004-NSCondition[61699:2558416] 消费一个 还剩 count 0
ion[61699:2558415] 生产一个 现有 count 1
2021-08-19 12:32:31.577360+0800 004-NSCondition[61699:2558419] 消费一个 还剩 count 0
2021-08-19 12:32:31.577156+0800 004-NSCondition[61699:2558417] 生产一个 现有 count 1
2021-08-19 12:32:31.577567+0800 004-NSCondition[61699:2558418] 等待 count 0
2021-08-19 12:32:31.577779+0800 004-NSCondition[61699:2558420] 生产一个 现有 count 1
2021-08-19 12:32:31.578487+0800 004-NSCondition[61699:2558415] 生产一个 现有 count 2
2021-08-19 12:32:31.578681+0800 004-NSCondition[61699:2558428] 消费一个 还剩 count 1
2021-08-19 12:32:31.578817+0800 004-NSCondition[61699:2558429] 消费一个 还剩 count 0
2021-08-19 12:32:31.578941+0800 004-NSCondition[61699:2558416] 生产一个 现有 count 1
2021-08-19 12:32:31.579155+0800 004-NSCondition[61699:2558419] 生产一个 现有 count 2
2021-08-19 12:32:31.579322+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 1
2021-08-19 12:32:31.580203+0800 004-NSCondition[61699:2558418] 消费一个 还剩 count 0
2021-08-19 12:32:31.580384+0800 004-NSCondition[61699:2558417] 等待 count 0
2021-08-19 12:32:31.580626+0800 004-NSCondition[61699:2558416] 生产一个 现有 count 1
2021-08-19 12:32:31.580901+0800 004-NSCondition[61699:2558428] 生产一个 现有 count 2
2021-08-19 12:32:31.581122+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 1
2021-08-19 12:32:31.581326+0800 004-NSCondition[61699:2558419] 消费一个 还剩 count 0
2021-08-19 12:32:31.581727+0800 004-NSCondition[61699:2558415] 生产一个 现有 count 2
2021-08-19 12:32:31.581579+0800 004-NSCondition[61699:2558429] 生产一个 现有 count 1
2021-08-19 12:32:31.586054+0800 004-NSCondition[61699:2558432] 生产一个 现有 count 1
2021-08-19 12:32:31.585909+0800 004-NSCondition[61699:2558431] 等待 count 0
2021-08-19 12:32:31.582528+0800 004-NSCondition[61699:2558417] 消费一个 还剩 count 0
2021-08-19 12:32:31.582353+0800 004-NSCondition[61699:2558416] 生产一个 现有 count 1
2021-08-19 12:32:31.585832+0800 004-NSCondition[61699:2558430] 消费一个 还剩 count 0
2021-08-19 12:32:31.582138+0800 004-NSCondition[61699:2558428] 消费一个 还剩 count 0
2021-08-19 12:32:31.582755+0800 004-NSCondition[61699:2558418] 生产一个 现有 count 1
2021-08-19 12:32:31.581933+0800 004-NSCondition[61699:2558420] 消费一个 还剩 count 1
2021-08-19 12:32:31.590021+0800 004-NSCondition[61699:2558419] 生产一个 现有 count 2
2021-08-19 12:32:31.590240+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 1
2021-08-19 12:32:31.590317+0800 004-NSCondition[61699:2558429] 消费一个 还剩 count 0
2021-08-19 12:32:31.590954+0800 004-NSCondition[61699:2558432] 生产一个 现有 count 1
2021-08-19 12:32:31.592834+0800 004-NSCondition[61699:2558431] 消费一个 还剩 count 0
2021-08-19 12:32:31.594283+0800 004-NSCondition[61699:2558419] 生产一个 现有 count 1
2021-08-19 12:32:31.596020+0800 004-NSCondition[61699:2558415] 等待 count 0
2021-08-19 12:32:31.595991+0800 004-NSCondition[61699:2558429] 消费一个 还剩 count 0
2021-08-19 12:32:31.596064+0800 004-NSCondition[61699:2558432] 生产一个 现有 count 1
2021-08-19 12:32:31.596265+0800 004-NSCondition[61699:2558417] 生产一个 现有 count 2
2021-08-19 12:32:31.596612+0800 004-NSCondition[61699:2558428] 消费一个 还剩 count 1
2021-08-19 12:32:31.596658+0800 004-NSCondition[61699:2558430] 消费一个 还剩 count 0
2021-08-19 12:32:31.596851+0800 004-NSCondition[61699:2558431] 生产一个 现有 count 1
2021-08-19 12:32:31.596938+0800 004-NSCondition[61699:2558416] 生产一个 现有 count 2
2021-08-19 12:32:31.597300+0800 004-NSCondition[61699:2558419] 消费一个 还剩 count 1
2021-08-19 12:32:31.597420+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 0
2021-08-19 12:32:31.597544+08002021-08-19 12:32:31.597765+0800 004-NSCondition[61699:2558420] 生产一个 现有 count 1
2021-08-19 12:32:31.597980+0800 004-NSCondition[61699:2558418] 生产一个 现有 count 2
2021-08-19 12:32:31.598215+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 1
2021-08-19 12:32:31.598425+0800 004-NSCondition[61699:2558431] 消费一个 还剩 count 0
2021-08-19 12:32:31.598628+0800 004-NSCondition[61699:2558417] 生产一个 现有 count 1
2021-08-19 12:32:31.598916+0800 004-NSCondition[61699:2558428] 生产一个 现有 count 2
2021-08-19 12:32:31.599191+0800 004-NSCondition[61699:2558419] 消费一个 还剩 count 1
2021-08-19 12:32:31.599271+0800 004-NSCondition[61699:2558436] 消费一个 还剩 count 0
2021-08-19 12:32:31.599403+0800 004-NSCondition[61699:2558437] 生产一个 现有 count 1
2021-08-19 12:32:31.599505+0800 004-NSCondition[61699:2558416] 生产一个 现有 count 2
2021-08-19 12:32:31.599829+0800 004-NSCondition[61699:2558430] 消费一个 还剩 count 1
2021-08-19 12:32:31.600045+0800 004-NSCondition[61699:2558429] 消费一个 还剩 count 0
2021-08-19 12:32:31.603315+0800 004-NSCondition[61699:2558438] 消费一个 还剩 count 0
2021-08-19 12:32:31.603430+0800 004-NSCondition[61699:2558439] 生产一个 现有 count 1
2021-08-19 12:32:31.603631+0800 004-NSCondition[61699:2558440] 生产一个 现有 count 1
2021-08-19 12:32:31.604509+0800 004-NSCondition[61699:2558441] 消费一个 还剩 count 0
2021-08-19 12:32:31.604668+0800 004-NSCondition[61699:2558442] 生产一个 现有 count 1
2021-08-19 12:32:31.604820+0800 004-NSCondition[61699:2558443] 生产一个 现有 count 2
2021-08-19 12:32:31.604892+0800 004-NSCondition[61699:2558444] 消费一个 还剩 count 1
2021-08-19 12:32:31.604991+0800 004-NSCondition[61699:2558445] 消费一个 还剩 count 0
2021-08-19 12:32:31.605167+0800 004-NSCondition[61699:2558446] 生产一个 现有 count 1
2021-08-19 12:32:31.607993+0800 004-NSCondition[61699:2558448] 消费一个 还剩 count 0
2021-08-19 12:32:31.614513+0800 004-NSCondition[61699:2558450] 生产一个 现有 count 2
2021-08-19 12:32:31.608386+0800 004-NSCondition[61699:2558447] 生产一个 现有 count 1
2021-08-19 12:32:31.617526+0800 004-NSCondition[61699:2558452] 消费一个 还剩 count 1
2021-08-19 12:32:31.615824+0800 004-NSCondition[61699:2558449] 消费一个 还剩 count 1
2021-08-19 12:32:31.617554+0800 004-NSCondition[61699:2558456] 生产一个 现有 count 2
2021-08-19 12:32:31.617563+0800 004-NSCondition[61699:2558457] 消费一个 还剩 count 0
2021-08-19 12:32:31.617662+0800 004-NSCondition[61699:2558459] 生产一个 现有 count 2
004-NSCondition[61699:2558432] 等待 count 0
2021-08-19 12:32:31.617661+0800 004-NSCondition[61699:2558458] 生产一个 现有 count 1
2021-08-19 12:32:31.618536+0800 004-NSCondition[61699:2558415] 消费一个 还剩 count 1
2021-08-19 12:32:31.618826+0800 004-NSCondition[61699:2558431] 消费一个 还剩 count 0
2021-08-19 12:32:31.619701+0800 004-NSCondition[61699:2558418] 生产一个 现有 count 1
2021-08-19 12:32:31.620013+0800 004-NSCondition[61699:2558430] 生产一个 现有 count 2
2021-08-19 12:32:31.620339+0800 004-NSCondition[61699:2558437] 消费一个 还剩 count 1
2021-08-19 12:32:31.620765+0800 004-NSCondition[61699:2558461] 生产一个 现有 count 1
2021-08-19 12:32:31.620832+0800 004-NSCondition[61699:2558460] 消费一个 还剩 count 0
2021-08-19 12:32:31.621156+0800 004-NSCondition[61699:2558436] 消费一个 还剩 count 0
2021-08-19 12:32:31.621179+0800 004-NSCondition[61699:2558462] 生产一个 现有 count 1
2021-08-19 12:32:31.621463+0800 004-NSCondition[61699:2558420] 消费一个 还剩 count 0
2021-08-19 12:32:31.622799+0800 004-NSCondition[61699:2558428] 生产一个 现有 count 1
2021-08-19 12:32:31.623678+0800 004-NSCondition[61699:2558464] 生产一个 现有 count 2
2021-08-19 12:32:31.623920+0800 004-NSCondition[61699:2558466] 消费一个 还剩 count 1
2021-08-19 12:32:31.624055+0800 004-NSCondition[61699:2558417] 消费一个 还剩 count 0
2021-08-19 12:32:31.624638+0800 004-NSCondition[61699:2558420] 生产一个 现有 count 2
2021-08-19 12:32:31.624628+0800 004-NSCondition[61699:2558465] 生产一个 现有 count 1
2021-08-19 12:32:31.624716+0800 004-NSCondition[61699:2558467] 消费一个 还剩 count 1
2021-08-19 12:32:31.625252+0800 004-NSCondition[61699:2558474] 消费一个 还剩 count 1
2021-08-19 12:32:31.624734+0800 004-NSCondition[61699:2558468] 消费一个 还剩 count 0
2021-08-19 12:32:31.624853+0800 004-NSCondition[61699:2558462] 生产一个 现有 count 1
2021-08-19 12:32:31.625028+0800 004-NSCondition[61699:2558469] 生产一个 现有 count 2
2021-08-19 12:32:31.625066+0800 004-NSCondition[61699:2558470] 消费一个 还剩 count 1
2021-08-19 12:32:31.625128+0800 004-NSCondition[61699:2558471] 消费一个 还剩 count 0
2021-08-19 12:32:31.625179+0800 004-NSCondition[61699:2558472] 生产一个 现有 count 1
2021-08-19 12:32:31.625221+0800 004-NSCondition[61699:2558473] 生产一个 现有 count 2
2021-08-19 12:32:31.625720+0800 004-NSCondition[61699:2558463] 消费一个 还剩 count 0
2021-08-19 12:32:31.625877+0800 004-NSCondition[61699:2558475] 生产一个 现有 count 1
2021-08-19 12:32:31.626032+0800 004-NSCondition[61699:2558476] 生产一个 现有 count 2
2021-08-19 12:32:31.626065+0800 004-NSCondition[61699:2558460] 消费一个 还剩 count 1
2021-08-19 12:32:31.626362+0800 004-NSCondition[61699:2558461] 消费一个 还剩 count 0
2021-08-19 12:32:31.626834+0800 004-NSCondition[61699:2558465] 生产一个 现有 count 1
2021-08-19 12:32:31.627117+0800 004-NSCondition[61699:2558478] 生产一个 现有 count 1
2021-08-19 12:32:31.627128+0800 004-NSCondition[61699:2558479] 消费一个 还剩 count 0
2021-08-19 12:32:31.627144+0800 004-NSCondition[61699:2558477] 消费一个 还剩 count 0
2021-08-19 12:32:31.627234+0800 004-NSCondition[61699:2558480] 生产一个 现有 count 1
2021-08-19 12:32:31.627424+0800 004-NSCondition[61699:2558420] 生产一个 现有 count 2
2021-08-19 12:32:31.627809+0800 004-NSCondition[61699:2558417] 消费一个 还剩 count 1
2021-08-19 12:32:31.628260+0800 004-NSCondition[61699:2558461] 消费一个 还剩 count 0
2021-08-19 12:32:31.628504+0800 004-NSCondition[61699:2558476] 生产一个 现有 count 1
2021-08-19 12:32:31.628862+0800 004-NSCondition[61699:2558475] 生产一个 现有 count 2
2021-08-19 12:32:31.629417+0800 004-NSCondition[61699:2558477] 消费一个 还剩 count 1
2021-08-19 12:32:31.629616+0800 004-NSCondition[61699:2558479] 消费一个 还剩 count 0
2021-08-19 12:32:31.630033+0800 004-NSCondition[61699:2558472] 生产一个 现有 count 1
2021-08-19 12:32:31.630247+0800 004-NSCondition[61699:2558481] 生产一个 现有 count 2
2021-08-19 12:32:31.630305+0800 004-NSCondition[61699:2558483] 消费一个 还剩 count 1
2021-08-19 12:32:31.630336+0800 004-NSCondition[61699:2558482] 消费一个 还剩 count 0
2021-08-19 12:32:31.630432+0800 004-NSCondition[61699:2558484] 生产一个 现有 count 1
2021-08-19 12:32:31.630523+0800 004-NSCondition[61699:2558470] 生产一个 现有 count 2
2021-08-19 12:32:31.630960+0800 004-NSCondition[61699:2558471] 消费一个 还剩 count 1
2021-08-19 12:32:31.631647+0800 004-NSCondition[61699:2558469] 消费一个 还剩 count 0
2021-08-19 12:32:31.632209+0800 004-NSCondition[61699:2558482] 生产一个 现有 count 1
2021-08-19 12:32:31.632537+0800 004-NSCondition[61699:2558472] 生产一个 现有 count 2
2021-08-19 12:32:31.632867+0800 004-NSCondition[61699:2558479] 消费一个 还剩 count 1
2021-08-19 12:32:31.633231+0800 004-NSCondition[61699:2558481] 消费一个 还剩 count 0
2021-08-19 12:32:31.633453+0800 004-NSCondition[61699:2558486] 生产一个 现有 count 2
2021-08-19 12:32:31.633557+0800 004-NSCondition[61699:2558485] 生产一个 现有 count 1
2021-08-19 12:32:31.633761+0800 004-NSCondition[61699:2558487] 消费一个 还剩 count 0
2021-08-19 12:32:31.633651+0800 004-NSCondition[61699:2558483] 消费一个 还剩 count 1
2021-08-19 12:32:31.633877+0800 004-NSCondition[61699:2558488] 生产一个 现有 count 1
2021-08-19 12:32:31.634151+0800 004-NSCondition[61699:2558479] 生产一个 现有 count 2
2021-08-19 12:32:31.634313+0800 004-NSCondition[61699:2558472] 消费一个 还剩 count 1
2021-08-19 12:32:31.634702+0800 004-NSCondition[61699:2558481] 消费一个 还剩 count 0
2021-08-19 12:32:31.635145+0800 004-NSCondition[61699:2558482] 生产一个 现有 count 1
2021-08-19 12:32:31.635482+0800 004-NSCondition[61699:2558477] 生产一个 现有 count 2
2021-08-19 12:32:31.635839+0800 004-NSCondition[61699:2558475] 消费一个 还剩 count 1
2021-08-19 12:32:31.636292+0800 004-NSCondition[61699:2558463] 消费一个 还剩 count 0
2021-08-19 12:32:31.636546+0800 004-NSCondition[61699:2558489] 生产一个 现有 count 2
2021-08-19 12:32:31.636546+0800 004-NSCondition[61699:2558490] 生产一个 现有 count 1
2021-08-19 12:32:31.636866+0800 004-NSCondition[61699:2558473] 消费一个 还剩 count 1
2021-08-19 12:32:31.636938+0800 004-NSCondition[61699:2558491] 消费一个 还剩 count 0
2021-08-19 12:32:31.637352+0800 004-NSCondition[61699:2558481] 生产一个 现有 count 1
2021-08-19 12:32:31.637689+0800 004-NSCondition[61699:2558428] 生产一个 现有 count 2
2021-08-19 12:32:31.637912+0800 004-NSCondition[61699:2558437] 消费一个 还剩 count 1
2021-08-19 12:32:31.638501+0800 004-NSCondition[61699:2558430] 消费一个 还剩 count 0
2021-08-19 12:32:31.638799+0800 004-NSCondition[61699:2558468] 生产一个 现有 count 1
2021-08-19 12:32:31.639851+0800 004-NSCondition[61699:2558474] 生产一个 现有 count 2
2021-08-19 12:32:31.639993+0800 004-NSCondition[61699:2558462] 消费一个 还剩 count 1
2021-08-19 12:32:31.642834+0800 004-NSCondition[61699:2558467] 消费一个 还剩 count 0
2021-08-19 12:32:31.642873+0800 004-NSCondition[61699:2558468] 生产一个 现有 count 1
2021-08-19 12:32:31.643215+0800 004-NSCondition[61699:2558430] 生产一个 现有 count 2
2021-08-19 12:32:31.643502+0800 004-NSCondition[61699:2558462] 消费一个 还剩 count 1
2021-08-19 12:32:31.643811+0800 004-NSCondition[61699:2558474] 消费一个 还剩 count 0
2021-08-19 12:32:31.644165+0800 004-NSCondition[61699:2558437] 生产一个 现有 count 1
2021-08-19 12:32:31.644502+0800 004-NSCondition[61699:2558492] 生产一个 现有 count 2
2021-08-19 12:32:31.644558+0800 004-NSCondition[61699:2558481] 消费一个 还剩 count 1
2021-08-19 12:32:31.644801+0800 004-NSCondition[61699:2558491] 消费一个 还剩 count 0
2021-08-19 12:32:31.645154+0800 004-NSCondition[61699:2558418] 生产一个 现有 count 1
2021-08-19 12:32:31.645457+0800 004-NSCondition[61699:2558489] 生产一个 现有 count 2
2021-08-19 12:32:31.645743+0800 004-NSCondition[61699:2558463] 消费一个 还剩 count 1
2021-08-19 12:32:31.646066+0800 004-NSCondition[61699:2558476] 消费一个 还剩 count 0
2021-08-19 12:32:31.646408+0800 004-NSCondition[61699:2558461] 生产一个 现有 count 1
2021-08-19 12:32:31.646756+0800 004-NSCondition[61699:2558417] 生产一个 现有 count 2
2021-08-19 12:32:31.647050+0800 004-NSCondition[61699:2558489] 消费一个 还剩 count 1
2021-08-19 12:32:31.647431+0800 004-NSCondition[61699:2558418] 消费一个 还剩 count 0
2021-08-19 12:32:31.647801+0800 004-NSCondition[61699:2558475] 生产一个 现有 count 1
2021-08-19 12:32:31.648134+0800 004-NSCondition[61699:2558477] 生产一个 现有 count 2
2021-08-19 12:32:31.648604+0800 004-NSCondition[61699:2558482] 消费一个 还剩 count 1
2021-08-19 12:32:31.648885+0800 004-NSCondition[61699:2558476] 消费一个 还剩 count 0
2021-08-19 12:32:31.649077+0800 004-NSCondition[61699:2558461] 生产一个 现有 count 1
2021-08-19 12:32:31.649520+0800 004-NSCondition[61699:2558491] 生产一个 现有 count 2
2021-08-19 12:32:31.649883+0800 004-NSCondition[61699:2558463] 消费一个 还剩 count 1
2021-08-19 12:32:31.650396+0800 004-NSCondition[61699:2558420] 消费一个 还剩 count 0
2021-08-19 12:32:31.650818+0800 004-NSCondition[61699:2558476] 生产一个 现有 count 1
2021-08-19 12:32:31.651033+0800 004-NSCondition[61699:2558481] 生产一个 现有 count 2
2021-08-19 12:32:31.651356+0800 004-NSCondition[61699:2558482] 消费一个 还剩 count 1
2021-08-19 12:32:31.651692+0800 004-NSCondition[61699:2558477] 消费一个 还剩 count 0
2021-08-19 12:32:31.652120+0800 004-NSCondition[61699:2558475] 生产一个 现有 count 1
2021-08-19 12:32:31.652372+0800 004-NSCondition[61699:2558420] 生产一个 现有 count 2
2021-08-19 12:32:31.652710+0800 004-NSCondition[61699:2558463] 消费一个 还剩 count 1
2021-08-19 12:32:31.653357+0800 004-NSCondition[61699:2558491] 生产一个 现有 count 1
2021-08-19 12:32:31.653357+0800 004-NSCondition[61699:2558480] 消费一个 还剩 count 0
2021-08-19 12:32:31.666438+0800 004-NSCondition[61699:2558432] 消费一个 还剩 count 0
这里出现消费一个,再消费一个的情况,因为我们生产一个,消费一个,这才是合理的逻辑,这里出现了数据混乱。
我们加上锁,执行,如下:
2021-08-19 12:36:07.780594+0800 004-NSCondition[61773:2562661] 生产一个 现有 count 1
2021-08-19 12:36:07.780827+0800 004-NSCondition[61773:2562661] 生产一个 现有 count 2
2021-08-19 12:36:07.781001+0800 004-NSCondition[61773:2562656] 消费一个 还剩 count 1
2021-08-19 12:36:07.781145+0800 004-NSCondition[61773:2562656] 消费一个 还剩 count 0
2021-08-19 12:36:07.781324+0800 004-NSCondition[61773:2562656] 生产一个 现有 count 1
2021-08-19 12:36:07.781605+0800 004-NSCondition[61773:2562661] 消费一个 还剩 count 0
2021-08-19 12:36:07.781761+0800 004-NSCondition[61773:2562659] 生产一个 现有 count 1
2021-08-19 12:36:07.781901+0800 004-NSCondition[61773:2562658] 消费一个 还剩 count 0
2021-08-19 12:36:07.782335+0800 004-NSCondition[61773:2562664] 生产一个 现有 count 1
2021-08-19 12:36:07.782840+0800 004-NSCondition[61773:2562657] 消费一个 还剩 count 0
2021-08-19 12:36:07.783372+0800 004-NSCondition[61773:2562657] 等待 count 0
2021-08-19 12:36:07.783920+0800 004-NSCondition[61773:2562656] 生产一个 现有 count 1
2021-08-19 12:36:07.784388+0800 004-NSCondition[61773:2562657] 消费一个 还剩 count 0
2021-08-19 12:36:07.784842+0800 004-NSCondition[61773:2562659] 等待 count 0
2021-08-19 12:36:07.785240+0800 004-NSCondition[61773:2562658] 等待 count 0
2021-08-19 12:36:07.785651+0800 004-NSCondition[61773:2562664] 生产一个 现有 count 1
2021-08-19 12:36:07.790800+0800 004-NSCondition[61773:2562719] 生产一个 现有 count 2
2021-08-19 12:36:07.791454+0800 004-NSCondition[61773:2562671] 生产一个 现有 count 3
2021-08-19 12:36:07.792516+0800 004-NSCondition[61773:2562673] 生产一个 现有 count 4
2021-08-19 12:36:07.793068+0800 004-NSCondition[61773:2562672] 消费一个 还剩 count 3
2021-08-19 12:36:07.793829+0800 004-NSCondition[61773:2562672] 生产一个 现有 count 4
2021-08-19 12:36:07.794326+0800 004-NSCondition[61773:2562656] 生产一个 现有 count 5
2021-08-19 12:36:07.794915+0800 004-NSCondition[61773:2562656] 消费一个 还剩 count 4
2021-08-19 12:36:07.795709+0800 004-NSCondition[61773:2562656] 生产一个 现有 count 5
2021-08-19 12:36:07.796736+0800 004-NSCondition[61773:2562675] 生产一个 现有 count 6
2021-08-19 12:36:07.797724+0800 004-NSCondition[61773:2562676] 生产一个 现有 count 7
2021-08-19 12:36:07.799552+0800 004-NSCondition[61773:2562676] 生产一个 现有 count 8
2021-08-19 12:36:07.802982+0800 004-NSCondition[61773:2562676] 消费一个 还剩 count 7
2021-08-19 12:36:07.803195+0800 004-NSCondition[61773:2562676] 消费一个 还剩 count 6
2021-08-19 12:36:07.803661+0800 004-NSCondition[61773:2562680] 生产一个 现有 count 7
2021-08-19 12:36:07.806095+0800 004-NSCondition[61773:2562681] 消费一个 还剩 count 6
2021-08-19 12:36:07.806856+0800 004-NSCondition[61773:2562682] 消费一个 还剩 count 5
2021-08-19 12:36:07.807966+0800 004-NSCondition[61773:2562683] 生产一个 现有 count 6
2021-08-19 12:36:07.808404+0800 004-NSCondition[61773:2562684] 生产一个 现有 count 7
2021-08-19 12:36:07.809210+0800 004-NSCondition[61773:2562684] 消费一个 还剩 count 6
2021-08-19 12:36:07.809602+0800 004-NSCondition[61773:2562684] 生产一个 现有 count 7
2021-08-19 12:36:07.809905+0800 004-NSCondition[61773:2562684] 生产一个 现有 count 8
2021-08-19 12:36:07.810297+0800 004-NSCondition[61773:2562684] 消费一个 还剩 count 7
2021-08-19 12:36:07.810953+0800 004-NSCondition[61773:2562684] 消费一个 还剩 count 6
2021-08-19 12:36:07.811457+0800 004-NSCondition[61773:2562690] 消费一个 还剩 count 5
2021-08-19 12:36:07.813341+0800 004-NSCondition[61773:2562690] 生产一个 现有 count 6
2021-08-19 12:36:07.821657+0800 004-NSCondition[61773:2562690] 消费一个 还剩 count 5
2021-08-19 12:36:07.823451+0800 004-NSCondition[61773:2562690] 消费一个 还剩 count 4
2021-08-19 12:36:07.824456+0800 004-NSCondition[61773:2562690] 生产一个 现有 count 5
2021-08-19 12:36:07.824940+0800 004-NSCondition[61773:2562695] 生产一个 现有 count 6
2021-08-19 12:36:07.825340+0800 004-NSCondition[61773:2562696] 生产一个 现有 count 7
2021-08-19 12:36:07.826224+0800 004-NSCondition[61773:2562696] 消费一个 还剩 count 6
2021-08-19 12:36:07.827103+0800 004-NSCondition[61773:2562698] 消费一个 还剩 count 5
2021-08-19 12:36:07.827632+0800 004-NSCondition[61773:2562699] 生产一个 现有 count 6
2021-08-19 12:36:07.828368+0800 004-NSCondition[61773:2562700] 生产一个 现有 count 7
2021-08-19 12:36:07.828643+0800 004-NSCondition[61773:2562701] 消费一个 还剩 count 6
2021-08-19 12:36:07.829148+0800 004-NSCondition[61773:2562702] 消费一个 还剩 count 5
2021-08-19 12:36:07.829479+0800 004-NSCondition[61773:2562702] 生产一个 现有 count 6
2021-08-19 12:36:07.829900+0800 004-NSCondition[61773:2562704] 生产一个 现有 count 7
2021-08-19 12:36:07.830165+0800 004-NSCondition[61773:2562704] 消费一个 还剩 count 6
2021-08-19 12:36:07.831331+0800 004-NSCondition[61773:2562704] 生产一个 现有 count 7
2021-08-19 12:36:07.831630+0800 004-NSCondition[61773:2562707] 生产一个 现有 count 8
2021-08-19 12:36:07.832299+0800 004-NSCondition[61773:2562708] 生产一个 现有 count 9
2021-08-19 12:36:07.832821+0800 004-NSCondition[61773:2562709] 消费一个 还剩 count 8
2021-08-19 12:36:07.833168+0800 004-NSCondition[61773:2562710] 消费一个 还剩 count 7
2021-08-19 12:36:07.833564+0800 004-NSCondition[61773:2562711] 生产一个 现有 count 8
2021-08-19 12:36:07.834048+0800 004-NSCondition[61773:2562712] 生产一个 现有 count 9
2021-08-19 12:36:07.835604+0800 004-NSCondition[61773:2562712] 消费一个 还剩 count 8
2021-08-19 12:36:07.835958+0800 004-NSCondition[61773:2562712] 生产一个 现有 count 9
2021-08-19 12:36:07.837085+0800 004-NSCondition[61773:2562715] 生产一个 现有 count 10
2021-08-19 12:36:07.837716+0800 004-NSCondition[61773:2562715] 消费一个 还剩 count 9
2021-08-19 12:36:07.838486+0800 004-NSCondition[61773:2562717] 消费一个 还剩 count 8
2021-08-19 12:36:07.839045+0800 004-NSCondition[61773:2562718] 消费一个 还剩 count 7
2021-08-19 12:36:07.839495+0800 004-NSCondition[61773:2562664] 生产一个 现有 count 8
2021-08-19 12:36:07.840166+0800 004-NSCondition[61773:2562664] 消费一个 还剩 count 7
2021-08-19 12:36:07.840493+0800 004-NSCondition[61773:2562670] 消费一个 还剩 count 6
2021-08-19 12:36:07.840734+0800 004-NSCondition[61773:2562658] 消费一个 还剩 count 5
2021-08-19 12:36:07.841315+0800 004-NSCondition[61773:2562719] 消费一个 还剩 count 4
2021-08-19 12:36:07.842119+0800 004-NSCondition[61773:2562719] 消费一个 还剩 count 3
2021-08-19 12:36:07.842486+0800 004-NSCondition[61773:2562719] 消费一个 还剩 count 2
2021-08-19 12:36:07.843162+0800 004-NSCondition[61773:2562661] 生产一个 现有 count 3
2021-08-19 12:36:07.843494+0800 004-NSCondition[61773:2562672] 消费一个 还剩 count 2
2021-08-19 12:36:07.843858+0800 004-NSCondition[61773:2562657] 消费一个 还剩 count 1
2021-08-19 12:36:07.844352+0800 004-NSCondition[61773:2562657] 消费一个 还剩 count 0
2021-08-19 12:36:07.845072+0800 004-NSCondition[61773:2562657] 生产一个 现有 count 1
2021-08-19 12:36:07.845303+0800 004-NSCondition[61773:2562721] 消费一个 还剩 count 0
2021-08-19 12:36:07.846187+0800 004-NSCondition[61773:2562722] 等待 count 0
2021-08-19 12:36:07.847638+0800 004-NSCondition[61773:2562723] 生产一个 现有 count 1
2021-08-19 12:36:07.848177+0800 004-NSCondition[61773:2562722] 消费一个 还剩 count 0
2021-08-19 12:36:07.848687+0800 004-NSCondition[61773:2562725] 等待 count 0
2021-08-19 12:36:07.849422+0800 004-NSCondition[61773:2562656] 等待 count 0
2021-08-19 12:36:07.850098+0800 004-NSCondition[61773:2562675] 生产一个 现有 count 1
2021-08-19 12:36:07.851221+0800 004-NSCondition[61773:2562725] 消费一个 还剩 count 0
2021-08-19 12:36:07.851680+0800 004-NSCondition[61773:2562678] 等待 count 0
2021-08-19 12:36:07.853248+0800 004-NSCondition[61773:2562679] 生产一个 现有 count 1
2021-08-19 12:36:07.853869+0800 004-NSCondition[61773:2562676] 生产一个 现有 count 2
2021-08-19 12:36:07.854954+0800 004-NSCondition[61773:2562678] 消费一个 还剩 count 1
2021-08-19 12:36:07.856389+0800 004-NSCondition[61773:2562681] 消费一个 还剩 count 0
2021-08-19 12:36:07.856895+0800 004-NSCondition[61773:2562682] 等待 count 0
2021-08-19 12:36:07.857306+0800 004-NSCondition[61773:2562683] 生产一个 现有 count 1
2021-08-19 12:36:07.857750+0800 004-NSCondition[61773:2562682] 消费一个 还剩 count 0
2021-08-19 12:36:07.860946+0800 004-NSCondition[61773:2562682] 生产一个 现有 count 1
2021-08-19 12:36:07.862151+0800 004-NSCondition[61773:2562729] 消费一个 还剩 count 0
2021-08-19 12:36:07.862393+0800 004-NSCondition[61773:2562686] 等待 count 0
2021-08-19 12:36:07.862660+0800 004-NSCondition[61773:2562687] 生产一个 现有 count 1
2021-08-19 12:36:07.862958+0800 004-NSCondition[61773:2562688] 生产一个 现有 count 2
2021-08-19 12:36:07.863792+0800 004-NSCondition[61773:2562688] 生产一个 现有 count 3
2021-08-19 12:36:07.869803+0800 004-NSCondition[61773:2562684] 生产一个 现有 count 4
2021-08-19 12:36:07.870514+0800 004-NSCondition[61773:2562684] 消费一个 还剩 count 3
2021-08-19 12:36:07.873553+0800 004-NSCondition[61773:2562692] 生产一个 现有 count 4
2021-08-19 12:36:07.874406+0800 004-NSCondition[61773:2562693] 消费一个 还剩 count 3
2021-08-19 12:36:07.875088+0800 004-NSCondition[61773:2562694] 消费一个 还剩 count 2
2021-08-19 12:36:07.876437+0800 004-NSCondition[61773:2562690] 生产一个 现有 count 3
2021-08-19 12:36:07.876813+0800 004-NSCondition[61773:2562695] 消费一个 还剩 count 2
2021-08-19 12:36:07.877435+0800 004-NSCondition[61773:2562697] 消费一个 还剩 count 1
2021-08-19 12:36:07.877936+0800 004-NSCondition[61773:2562696] 生产一个 现有 count 2
2021-08-19 12:36:07.878481+0800 004-NSCondition[61773:2562698] 生产一个 现有 count 3
2021-08-19 12:36:07.878839+0800 004-NSCondition[61773:2562699] 消费一个 还剩 count 2
2021-08-19 12:36:07.996559+0800 004-NSCondition[61773:2562700] 消费一个 还剩 count 1
2021-08-19 12:36:07.997821+0800 004-NSCondition[61773:2562701] 生产一个 现有 count 2
2021-08-19 12:36:07.999261+0800 004-NSCondition[61773:2562703] 生产一个 现有 count 3
2021-08-19 12:36:08.000533+0800 004-NSCondition[61773:2562702] 消费一个 还剩 count 2
2021-08-19 12:36:08.002534+0800 004-NSCondition[61773:2562705] 消费一个 还剩 count 1
2021-08-19 12:36:08.004080+0800 004-NSCondition[61773:2562705] 生产一个 现有 count 2
2021-08-19 12:36:08.005027+0800 004-NSCondition[61773:2562704] 生产一个 现有 count 3
2021-08-19 12:36:08.005297+0800 004-NSCondition[61773:2562707] 消费一个 还剩 count 2
2021-08-19 12:36:08.005540+0800 004-NSCondition[61773:2562708] 消费一个 还剩 count 1
2021-08-19 12:36:08.006059+0800 004-NSCondition[61773:2562709] 生产一个 现有 count 2
2021-08-19 12:36:08.006697+0800 004-NSCondition[61773:2562710] 生产一个 现有 count 3
2021-08-19 12:36:08.007570+0800 004-NSCondition[61773:2562711] 消费一个 还剩 count 2
2021-08-19 12:36:08.007763+0800 004-NSCondition[61773:2562711] 生产一个 现有 count 3
2021-08-19 12:36:08.007933+0800 004-NSCondition[61773:2562714] 消费一个 还剩 count 2
2021-08-19 12:36:08.008249+0800 004-NSCondition[61773:2562712] 生产一个 现有 count 3
2021-08-19 12:36:08.032662+0800 004-NSCondition[61773:2562716] 生产一个 现有 count 4
2021-08-19 12:36:08.033593+0800 004-NSCondition[61773:2562715] 消费一个 还剩 count 3
2021-08-19 12:36:08.034155+0800 004-NSCondition[61773:2562717] 生产一个 现有 count 4
2021-08-19 12:36:08.034951+0800 004-NSCondition[61773:2562718] 生产一个 现有 count 5
2021-08-19 12:36:08.036092+0800 004-NSCondition[61773:2562718] 消费一个 还剩 count 4
2021-08-19 12:36:08.037605+0800 004-NSCondition[61773:2562664] 消费一个 还剩 count 3
2021-08-19 12:36:08.038858+0800 004-NSCondition[61773:2562670] 生产一个 现有 count 4
2021-08-19 12:36:08.039862+0800 004-NSCondition[61773:2562658] 生产一个 现有 count 5
2021-08-19 12:36:08.040082+0800 004-NSCondition[61773:2562671] 消费一个 还剩 count 4
2021-08-19 12:36:08.040234+0800 004-NSCondition[61773:2562671] 生产一个 现有 count 5
2021-08-19 12:36:08.040361+0800 004-NSCondition[61773:2562671] 生产一个 现有 count 6
2021-08-19 12:36:08.055455+0800 004-NSCondition[61773:2562661] 生产一个 现有 count 7
2021-08-19 12:36:08.055733+0800 004-NSCondition[61773:2562661] 消费一个 还剩 count 6
2021-08-19 12:36:08.055960+0800 004-NSCondition[61773:2562674] 消费一个 还剩 count 5
2021-08-19 12:36:08.056177+0800 004-NSCondition[61773:2562720] 生产一个 现有 count 6
2021-08-19 12:36:08.056393+0800 004-NSCondition[61773:2562657] 生产一个 现有 count 7
2021-08-19 12:36:08.056605+0800 004-NSCondition[61773:2562721] 消费一个 还剩 count 6
2021-08-19 12:36:08.056774+0800 004-NSCondition[61773:2562721] 生产一个 现有 count 7
2021-08-19 12:36:08.057592+0800 004-NSCondition[61773:2562724] 生产一个 现有 count 8
2021-08-19 12:36:08.061280+0800 004-NSCondition[61773:2562722] 生产一个 现有 count 9
2021-08-19 12:36:08.070331+0800 004-NSCondition[61773:2562675] 生产一个 现有 count 10
2021-08-19 12:36:08.072080+0800 004-NSCondition[61773:2562677] 消费一个 还剩 count 9
2021-08-19 12:36:08.073954+0800 004-NSCondition[61773:2562725] 消费一个 还剩 count 8
2021-08-19 12:36:08.074166+0800 004-NSCondition[61773:2562679] 消费一个 还剩 count 7
2021-08-19 12:36:08.074341+0800 004-NSCondition[61773:2562656] 消费一个 还剩 count 6
2021-08-19 12:36:08.074597+0800 004-NSCondition[61773:2562680] 生产一个 现有 count 7
2021-08-19 12:36:08.075125+0800 004-NSCondition[61773:2562676] 生产一个 现有 count 8
2021-08-19 12:36:08.075694+0800 004-NSCondition[61773:2562678] 生产一个 现有 count 9
2021-08-19 12:36:08.078484+0800 004-NSCondition[61773:2562681] 消费一个 还剩 count 8
2021-08-19 12:36:08.088618+0800 004-NSCondition[61773:2562728] 生产一个 现有 count 9
2021-08-19 12:36:08.091309+0800 004-NSCondition[61773:2562683] 消费一个 还剩 count 8
2021-08-19 12:36:08.091871+0800 004-NSCondition[61773:2562685] 消费一个 还剩 count 7
2021-08-19 12:36:08.094234+0800 004-NSCondition[61773:2562682] 生产一个 现有 count 8
2021-08-19 12:36:08.100436+0800 004-NSCondition[61773:2562729] 消费一个 还剩 count 7
2021-08-19 12:36:08.104815+0800 004-NSCondition[61773:2562686] 消费一个 还剩 count 6
2021-08-19 12:36:08.104990+0800 004-NSCondition[61773:2562687] 消费一个 还剩 count 5
2021-08-19 12:36:08.105155+0800 004-NSCondition[61773:2562689] 消费一个 还剩 count 4
2021-08-19 12:36:08.105328+0800 004-NSCondition[61773:2562688] 生产一个 现有 count 5
2021-08-19 12:36:08.105493+0800 004-NSCondition[61773:2562691] 生产一个 现有 count 6
2021-08-19 12:36:08.105647+0800 004-NSCondition[61773:2562684] 消费一个 还剩 count 5
2021-08-19 12:36:08.105779+0800 004-NSCondition[61773:2562692] 生产一个 现有 count 6
2021-08-19 12:36:08.106091+0800 004-NSCondition[61773:2562693] 生产一个 现有 count 7
2021-08-19 12:36:08.106554+0800 004-NSCondition[61773:2562694] 消费一个 还剩 count 6
2021-08-19 12:36:08.107011+0800 004-NSCondition[61773:2562690] 消费一个 还剩 count 5
2021-08-19 12:36:08.107548+0800 004-NSCondition[61773:2562695] 生产一个 现有 count 6
2021-08-19 12:36:08.119057+0800 004-NSCondition[61773:2562697] 生产一个 现有 count 7
2021-08-19 12:36:08.119259+0800 004-NSCondition[61773:2562696] 消费一个 还剩 count 6
2021-08-19 12:36:08.119427+0800 004-NSCondition[61773:2562698] 消费一个 还剩 count 5
2021-08-19 12:36:08.119581+0800 004-NSCondition[61773:2562699] 生产一个 现有 count 6
2021-08-19 12:36:08.119880+0800 004-NSCondition[61773:2562700] 生产一个 现有 count 7
2021-08-19 12:36:08.120389+0800 004-NSCondition[61773:2562701] 消费一个 还剩 count 6
2021-08-19 12:36:08.120859+0800 004-NSCondition[61773:2562703] 消费一个 还剩 count 5
2021-08-19 12:36:08.121286+0800 004-NSCondition[61773:2562702] 生产一个 现有 count 6
2021-08-19 12:36:08.121767+0800 004-NSCondition[61773:2562706] 消费一个 还剩 count 5
2021-08-19 12:36:08.122098+0800 004-NSCondition[61773:2562705] 消费一个 还剩 count 4
2021-08-19 12:36:08.122469+0800 004-NSCondition[61773:2562704] 消费一个 还剩 count 3
2021-08-19 12:36:08.122896+0800 004-NSCondition[61773:2562707] 生产一个 现有 count 4
2021-08-19 12:36:08.123505+0800 004-NSCondition[61773:2562708] 生产一个 现有 count 5
2021-08-19 12:36:08.125252+0800 004-NSCondition[61773:2562709] 消费一个 还剩 count 4
2021-08-19 12:36:08.128056+0800 004-NSCondition[61773:2562710] 消费一个 还剩 count 3
2021-08-19 12:36:08.130918+0800 004-NSCondition[61773:2562713] 消费一个 还剩 count 2
2021-08-19 12:36:08.135223+0800 004-NSCondition[61773:2562711] 生产一个 现有 count 3
2021-08-19 12:36:08.136428+0800 004-NSCondition[61773:2562714] 消费一个 还剩 count 2
2021-08-19 12:36:08.136892+0800 004-NSCondition[61773:2562712] 消费一个 还剩 count 1
2021-08-19 12:36:08.137286+0800 004-NSCondition[61773:2562716] 生产一个 现有 count 2
2021-08-19 12:36:08.137652+0800 004-NSCondition[61773:2562715] 生产一个 现有 count 3
2021-08-19 12:36:08.138076+0800 004-NSCondition[61773:2562717] 消费一个 还剩 count 2
2021-08-19 12:36:08.138416+0800 004-NSCondition[61773:2562659] 消费一个 还剩 count 1
2021-08-19 12:36:08.139008+0800 004-NSCondition[61773:2562718] 生产一个 现有 count 2
2021-08-19 12:36:08.139530+0800 004-NSCondition[61773:2562664] 生产一个 现有 count 3
2021-08-19 12:36:08.139942+0800 004-NSCondition[61773:2562670] 消费一个 还剩 count 2
2021-08-19 12:36:08.140481+0800 004-NSCondition[61773:2562658] 消费一个 还剩 count 1
2021-08-19 12:36:08.141183+0800 004-NSCondition[61773:2562673] 生产一个 现有 count 2
2021-08-19 12:36:08.144723+0800 004-NSCondition[61773:2562719] 生产一个 现有 count 3
2021-08-19 12:36:08.148864+0800 004-NSCondition[61773:2562671] 消费一个 还剩 count 2
2021-08-19 12:36:08.151855+0800 004-NSCondition[61773:2562672] 消费一个 还剩 count 1
2021-08-19 12:36:08.153266+0800 004-NSCondition[61773:2562661] 生产一个 现有 count 2
2021-08-19 12:36:08.153638+0800 004-NSCondition[61773:2562674] 生产一个 现有 count 3
2021-08-19 12:36:08.154041+0800 004-NSCondition[61773:2562720] 消费一个 还剩 count 2
2021-08-19 12:36:08.154577+0800 004-NSCondition[61773:2562657] 消费一个 还剩 count 1
2021-08-19 12:36:08.155147+0800 004-NSCondition[61773:2562723] 消费一个 还剩 count 0
这里就没有出现过度消费的情况,生产一个,消费一个,如self.ticketCount==0,就出现信号等待。
生产进行加锁,消费加锁保证了事务的安全。
4 Foundation源码关于锁的封装
因为NSLock在Foundation框架中,没有开源 我们要分析NSLock的底层,怎么办呢,
我们可以通过swift的foundation开源代码来分析。
我们能一系列的分析NLock的lock是NSLocking的协议方法,只要实现NSLocking协议,就会有lock和unlock两个方法,这个时候结合swift的Foundation源码看,找到如下代码。
public protocol NSLocking {
func lock()
func unlock()
}
我们再看下它的实现
open class NSLock: NSObject, NSLocking {
internal var mutex = _MutexPointer.allocate(capacity: 1)
#if os(macOS) || os(iOS) || os(Windows)
private var timeoutCond = _ConditionVariablePointer.allocate(capacity: 1)
private var timeoutMutex = _MutexPointer.allocate(capacity: 1)
#endif
public override init() {
#if os(Windows)
InitializeSRWLock(mutex)
InitializeConditionVariable(timeoutCond)
InitializeSRWLock(timeoutMutex)
#else
pthread_mutex_init(mutex, nil)
#if os(macOS) || os(iOS)
pthread_cond_init(timeoutCond, nil)
pthread_mutex_init(timeoutMutex, nil)
#endif
#endif
}
deinit {
#if os(Windows)
// SRWLocks do not need to be explicitly destroyed
#else
pthread_mutex_destroy(mutex)
#endif
mutex.deinitialize(count: 1)
mutex.deallocate()
#if os(macOS) || os(iOS) || os(Windows)
deallocateTimedLockData(cond: timeoutCond, mutex: timeoutMutex)
#endif
}
open func lock() {
#if os(Windows)
AcquireSRWLockExclusive(mutex)
#else
pthread_mutex_lock(mutex)
#endif
}
open func unlock() {
#if os(Windows)
ReleaseSRWLockExclusive(mutex)
AcquireSRWLockExclusive(timeoutMutex)
WakeAllConditionVariable(timeoutCond)
ReleaseSRWLockExclusive(timeoutMutex)
#else
pthread_mutex_unlock(mutex)
#if os(macOS) || os(iOS)
// Wakeup any threads waiting in lock(before:)
pthread_mutex_lock(timeoutMutex)
pthread_cond_broadcast(timeoutCond)
pthread_mutex_unlock(timeoutMutex)
#endif
#endif
}
open func `try`() -> Bool {
#if os(Windows)
return TryAcquireSRWLockExclusive(mutex) != 0
#else
return pthread_mutex_trylock(mutex) == 0
#endif
}
open func lock(before limit: Date) -> Bool {
#if os(Windows)
if TryAcquireSRWLockExclusive(mutex) != 0 {
return true
}
#else
if pthread_mutex_trylock(mutex) == 0 {
return true
}
#endif
#if os(macOS) || os(iOS) || os(Windows)
return timedLock(mutex: mutex, endTime: limit, using: timeoutCond, with: timeoutMutex)
#else
guard var endTime = timeSpecFrom(date: limit) else {
return false
}
return pthread_mutex_timedlock(mutex, &endTime) == 0
#endif
}
open var name: String?
}
找到这段代码,其中这里这段代码:
#if os(Windows)
InitializeSRWLock(mutex)
InitializeConditionVariable(timeoutCond)
InitializeSRWLock(timeoutMutex)
#else
pthread_mutex_init(mutex, nil)
#if os(macOS) || os(iOS)
pthread_cond_init(timeoutCond, nil)
pthread_mutex_init(timeoutMutex, nil)
#endif
#endif
底层使用pthread封装 .
我们再来看下NSRecursiveLock锁的原理,通过搜索,找到以下代码:
open class NSRecursiveLock: NSObject, NSLocking {
internal var mutex = _RecursiveMutexPointer.allocate(capacity: 1)
#if os(macOS) || os(iOS) || os(Windows)
private var timeoutCond = _ConditionVariablePointer.allocate(capacity: 1)
private var timeoutMutex = _MutexPointer.allocate(capacity: 1)
#endif
public override init() {
super.init()
#if os(Windows)
InitializeCriticalSection(mutex)
InitializeConditionVariable(timeoutCond)
InitializeSRWLock(timeoutMutex)
#else
#if CYGWIN
var attrib : pthread_mutexattr_t? = nil
#else
var attrib = pthread_mutexattr_t()
#endif
withUnsafeMutablePointer(to: &attrib) { attrs in
pthread_mutexattr_init(attrs)
pthread_mutexattr_settype(attrs, Int32(PTHREAD_MUTEX_RECURSIVE))
pthread_mutex_init(mutex, attrs)
}
#if os(macOS) || os(iOS)
pthread_cond_init(timeoutCond, nil)
pthread_mutex_init(timeoutMutex, nil)
#endif
#endif
}
deinit {
#if os(Windows)
DeleteCriticalSection(mutex)
#else
pthread_mutex_destroy(mutex)
#endif
mutex.deinitialize(count: 1)
mutex.deallocate()
#if os(macOS) || os(iOS) || os(Windows)
deallocateTimedLockData(cond: timeoutCond, mutex: timeoutMutex)
#endif
}
open func lock() {
#if os(Windows)
EnterCriticalSection(mutex)
#else
pthread_mutex_lock(mutex)
#endif
}
open func unlock() {
#if os(Windows)
LeaveCriticalSection(mutex)
AcquireSRWLockExclusive(timeoutMutex)
WakeAllConditionVariable(timeoutCond)
ReleaseSRWLockExclusive(timeoutMutex)
#else
pthread_mutex_unlock(mutex)
#if os(macOS) || os(iOS)
// Wakeup any threads waiting in lock(before:)
pthread_mutex_lock(timeoutMutex)
pthread_cond_broadcast(timeoutCond)
pthread_mutex_unlock(timeoutMutex)
#endif
#endif
}
open func `try`() -> Bool {
#if os(Windows)
return TryEnterCriticalSection(mutex)
#else
return pthread_mutex_trylock(mutex) == 0
#endif
}
open func lock(before limit: Date) -> Bool {
#if os(Windows)
if TryEnterCriticalSection(mutex) {
return true
}
#else
if pthread_mutex_trylock(mutex) == 0 {
return true
}
#endif
#if os(macOS) || os(iOS) || os(Windows)
return timedLock(mutex: mutex, endTime: limit, using: timeoutCond, with: timeoutMutex)
#else
guard var endTime = timeSpecFrom(date: limit) else {
return false
}
return pthread_mutex_timedlock(mutex, &endTime) == 0
#endif
}
open var name: String?
}
它的源码中,有这样一段
#if os(macOS) || os(iOS)
pthread_cond_init(timeoutCond, nil)
pthread_mutex_init(timeoutMutex, nil)
#endif
#endif
不难看出也是在底层封装了pthread。
NSLock和NSRecursiveLock底层都是用pthread封装的,为什么NSLock不是递归,NSRecursiveLock是递归呢,我们来看下。
NSRecursiveLock
#if CYGWIN
var attrib : pthread_mutexattr_t? = nil
#else
var attrib = pthread_mutexattr_t()
#endif
withUnsafeMutablePointer(to: &attrib) { attrs in
pthread_mutexattr_init(attrs)
pthread_mutexattr_settype(attrs, Int32(PTHREAD_MUTEX_RECURSIVE))
pthread_mutex_init(mutex, attrs)
与
pthread_mutexattr_settype(attrs, Int32(PTHREAD_MUTEX_RECURSIVE))
有这些代码,而NSLock没有这些东西。
我们再来看NSCondition,找到如下代码:
open class NSCondition: NSObject, NSLocking {
internal var mutex = _MutexPointer.allocate(capacity: 1)
internal var cond = _ConditionVariablePointer.allocate(capacity: 1)
public override init() {
#if os(Windows)
InitializeSRWLock(mutex)
InitializeConditionVariable(cond)
#else
pthread_mutex_init(mutex, nil)
pthread_cond_init(cond, nil)
#endif
}
deinit {
#if os(Windows)
// SRWLock do not need to be explicitly destroyed
#else
pthread_mutex_destroy(mutex)
pthread_cond_destroy(cond)
#endif
mutex.deinitialize(count: 1)
cond.deinitialize(count: 1)
mutex.deallocate()
cond.deallocate()
}
open func lock() {
#if os(Windows)
AcquireSRWLockExclusive(mutex)
#else
pthread_mutex_lock(mutex)
#endif
}
open func unlock() {
#if os(Windows)
ReleaseSRWLockExclusive(mutex)
#else
pthread_mutex_unlock(mutex)
#endif
}
open func wait() {
#if os(Windows)
SleepConditionVariableSRW(cond, mutex, WinSDK.INFINITE, 0)
#else
pthread_cond_wait(cond, mutex)
#endif
}
open func wait(until limit: Date) -> Bool {
#if os(Windows)
return SleepConditionVariableSRW(cond, mutex, timeoutFrom(date: limit), 0)
#else
guard var timeout = timeSpecFrom(date: limit) else {
return false
}
return pthread_cond_timedwait(cond, mutex, &timeout) == 0
#endif
}
open func signal() {
#if os(Windows)
WakeConditionVariable(cond)
#else
pthread_cond_signal(cond)
#endif
}
open func broadcast() {
#if os(Windows)
WakeAllConditionVariable(cond)
#else
// 汇编分析 - 猜 (多看多玩)
pthread_cond_broadcast(cond) // wait signal
#endif
}
open var name: String?
}
#if os(Windows)
private func timeoutFrom(date: Date) -> DWORD {
guard date.timeIntervalSinceNow > 0 else { return 0 }
return DWORD(date.timeIntervalSinceNow * 1000)
}
#else
private func timeSpecFrom(date: Date) -> timespec? {
guard date.timeIntervalSinceNow > 0 else {
return nil
}
let nsecPerSec: Int64 = 1_000_000_000
let interval = date.timeIntervalSince1970
let intervalNS = Int64(interval * Double(nsecPerSec))
return timespec(tv_sec: Int(intervalNS / nsecPerSec),
tv_nsec: Int(intervalNS % nsecPerSec))
}
这里同样也实现了NSLocking协议,同样也是在底层封装了pthread。
如果在没有源码的情况下我们该如何分析呢,我们就由NSConditionLock来举例,看看如何分析。
5 NSConditionLock分析
- (void)ro_testConditonLock{
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:2];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
[conditionLock lockWhenCondition:1];
NSLog(@"线程 1");
[conditionLock unlockWithCondition:0];
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
[conditionLock lockWhenCondition:2];
sleep(0.1);
NSLog(@"线程 2");
[conditionLock unlockWithCondition:1];
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[conditionLock lock];
NSLog(@"线程 3");
[conditionLock unlock];
});
}
这是分析的代码,这里的执行顺序是什么?
我们打印下,如图:
顺序是3,2,1。这里2和3是无序的,1一定是2之后执行,为什么呢, [[NSConditionLock alloc] initWithCondition:2];*这里initWithCondition等于2,也就是说条件是2 ,如果不等于2是不会执行的。
分析如下:
- 先进入线程1,发现条件不满足,就等待
- 这个时候进入线程2 ,发现条件满足,执行
- 线程执行后,条件变成1,线程1会执行
- 线程3是因为没有加条件,所以就先执行
我们发现 NSConditionLock与NSCondition有点像
- 他们有没有关系,我们接下来调试分析下。
- lockWhenCondition是如何控制的
- lockWhenCondition中的2是什么
- unlockWithCondition做了什么
针对这些疑问,我们断点调试下,还有一个-[NSConditionLock initWithCondition:]符号断点,如图:
在Foundation中-[NSConditionLock initWithCondition:]这个方法断住了,
这时候我们读取x0,x1寄存看下,如图
这里打印结果对应上了。
在这里我们可以通b跳转指令来查找流程,我们在bl指令的地方打上断点,调试,结果如下: - [NSConditionLock initWithCondition:]:
- [init: 2]
- -[NSConditionLock init]
- [NSConditionLock zone]
- [NSCondition allocWithZone]
- [NSCondition init]
从这里可以看出NSConditionLock封装了NSCondition,里面存储了value值。
lockWhenCondition与unlockWithCondition的流程是怎么样,我们再分析下,通过-[NSConditionLock lockWhenCondition:] 符号断点分析,如图
分析结果如下,lockWhenCondition流程:
- -[NSConditionLock lockWhenCondition:]
- [NSDate distantFuture]
- [NSConditionLock lockWhenCondition:(条件) beforeDate:]
- [NSCondition lock]
- [NSCondition waitUntilDate:]
- 返回1 不再等待,可以往下执行
- [NSCondition unlock]
unlockWithCondition流程:
- -[NSConditionLock unlockWithCondition:]
- [NSCondition lock]
- [NSCondition broadcast]
- [NSCondition unlock]
我们再对比一下源码
open class NSConditionLock : NSObject, NSLocking {
internal var _cond = NSCondition()
internal var _value: Int
internal var _thread: _swift_CFThreadRef?
public convenience override init() {
self.init(condition: 0)
}
public init(condition: Int) {
_value = condition
}
open func lock() {
let _ = lock(before: Date.distantFuture)
}
open func unlock() {
_cond.lock()
#if os(Windows)
_thread = INVALID_HANDLE_VALUE
#else
_thread = nil
#endif
_cond.broadcast()
_cond.unlock()
}
open var condition: Int {
return _value
}
open func lock(whenCondition condition: Int) {
let _ = lock(whenCondition: condition, before: Date.distantFuture)
}
open func `try`() -> Bool {
return lock(before: Date.distantPast)
}
open func tryLock(whenCondition condition: Int) -> Bool {
return lock(whenCondition: condition, before: Date.distantPast)
}
open func unlock(withCondition condition: Int) {
_cond.lock()
#if os(Windows)
_thread = INVALID_HANDLE_VALUE
#else
_thread = nil
#endif
_value = condition
_cond.broadcast()
_cond.unlock()
}
open func lock(before limit: Date) -> Bool {
_cond.lock()
while _thread != nil {
if !_cond.wait(until: limit) {
_cond.unlock()
return false
}
}
#if os(Windows)
_thread = GetCurrentThread()
#else
_thread = pthread_self()
#endif
_cond.unlock()
return true
}
open func lock(whenCondition condition: Int, before limit: Date) -> Bool {
_cond.lock()
while _thread != nil || _value != condition {
if !_cond.wait(until: limit) {
_cond.unlock()
return false
}
}
#if os(Windows)
_thread = GetCurrentThread()
#else
_thread = pthread_self()
#endif
_cond.unlock()
return true
}
open var name: String?
}
从以上代码可以看出,跟我们上面的得到的流程是一样的。
6 读写锁的简介
读写锁实际是⼀种特殊的互斥锁,它把对共享资源的访问者划分成读者和写者,读者只对共享资源进⾏读访问,写者则需要对共享资源进⾏写操作。这种锁相对于⾃旋锁⽽⾔,能提⾼并发性,因为在多处理器系统中,它允许同时有多个读者来访问共享资源,最⼤可能的读者数为实际的逻辑CPU数。
写者是排他性的,⼀个读写锁同时只能有⼀个写者或多个读者(与CPU数相关),但不能同时既有读者⼜有写者。在读写锁保持期间也是抢占失效的。如果读写锁当前没有读者,也没有写者,那么写者可以⽴刻获得读写锁,否则它必须⾃旋在那⾥,直到没有任何写者或读者。如果读写锁没有写者,那么读者可以⽴即获得该读写锁,否则读者必须⾃旋在那⾥,直到写者释放该读写锁。⼀次只有⼀个线程可以占有写模式的读写锁, 但是可以有多个线程同时占有读模式的读写锁.
正是因为这个特性,当读写锁是写加锁状态时, 在这个锁被解锁之前, 所有试图对这个锁加锁的线程都会被阻塞.当读写锁在读加锁状态时, 所有试图以读模式对它进⾏加锁的线程都可以得到访问权, 但是如果线程希望以写模式对此锁进⾏加锁, 它必须直到所有的线程释放锁.
通常, 当读写锁处于读模式锁住状态时, 如果有另外线程试图以写模式加锁, 读写锁通常会阻塞随后的读模式锁请求, 这样可以避免读模式锁⻓期占⽤, ⽽等待的写模式锁请求⻓期阻塞.
读写锁适合于对数据结构的读次数⽐写次数多得多的情况. 因为, 读模式锁定时可以共享, 以写模式锁住时意味着独占, 所以读写锁⼜叫共享-独占锁。
7 GCD实现读写锁
对于读写锁,我们需要实现以下几点:
- 多读单写,利用多条线程读出数据,单写:同一时刻操作只有一个线程操作这片内存空间
- 写写互斥
- 读写互斥
- 读写操作不能影响当前线程的执行
单写: 我们可以利用GCD的栅栏函数来实现,栅栏函数使我们在写操作的时候,前面读或写操作不能执行,保证写写互斥和读写互斥,因为我们要保证读写操作不能影响当前线程的执行, 所以我们就可以用dispatch_barrier_async这个函数来实现,不影响主业务执行。
多读:dispatch_sync和并发队列来实现。
GCD多读单写代码如下:
.h文件
#import
NS_ASSUME_NONNULL_BEGIN
@interface ReadWriteLock : NSObject
- (id)readDataWithKey:(NSString *)key;
- (void)writeDataWithKey:(NSString *)key value:(id)value;
@end
NS_ASSUME_NONNULL_END
.m文件
#import "ReadWriteLock.h"
@interface ReadWriteLock()
@property (strong, nonatomic) dispatch_queue_t queue;
@property (strong, nonatomic) NSMutableDictionary *dict;
@end
@implementation ReadWriteLock
- (id)init {
self = [super init];
if (self) {
}
return self;
}
- (id)readDataWithKey:(NSString *)key {
__block id value = nil;
dispatch_sync(self.queue, ^{
value = self.dict[key];
});
return value;
}
- (void)writeDataWithKey:(NSString *)key value:(id)value {
dispatch_barrier_async(self.queue, ^{
NSLog(@"写入:%@ ------- %@", value, [NSThread currentThread]);
[self.dict setValue:value forKey:key];
});
}
#pragma GET SET
- (dispatch_queue_t )queue {
if (!_queue) {
_queue = dispatch_queue_create("ro_robert_queue",DISPATCH_QUEUE_CONCURRENT);
}
return _queue;
}
- (NSMutableDictionary *)dict {
if (!_dict) {
_dict = [[NSMutableDictionary alloc] init];
}
return _dict;
}
@end
如果对以上代码有疑问,随时欢迎来交流
结语
这篇文章,我们分析了NSLock、NSCondition、NSConditionLock、NSRecursiveLock这几种锁的原理和流程,如有错误或者遗漏,请大家批评指正。