「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战」
多线程的竞争
现象描述
在实际场景中,一块资源可能被多个线程共享,也就是说多个线程可能会访问同一个资源、同一个对象、同一个变量,在这种情况下容易引发数据错乱和数据安全问题(如下图)
示例:
- (IBAction)threadLock:(UIButton *)sender {
self.ticketCount = 5;
self.thread01 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread01.name = @"售票员1";
self.thread02 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread02.name = @"售票员2";
self.thread03 = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread03.name = @"售票员3";
[self.thread01 start];
[self.thread02 start];
[self.thread03 start];
}
- (void)saleTicket{
while (1) {
NSLog(@"进行卖票-%@",[NSThread currentThread].name);
NSInteger count = self.ticketCount;
if (count > 0 ){
self.ticketCount = count - 1;
NSLog(@"%@卖了一张票,还剩%ld张",[NSThread currentThread].name,(long)self.ticketCount);
}else{
NSLog(@"票卖完了");
break;
}
}
}
log:
问题解决
针对以上情况,通过线程锁来解决以上问题。当线程A去访问数据源之前,先将数据源锁住,读取数据并运算,将结果写入数据源之后,将其解锁。当线程B再去访问数据源之前,再次将数据源加锁,读取数据并运算,结果写入数据源之后再将其解锁。这样就避免了多个线程同时访问数据而造成数据错误问题(如下图)
示例:
- (void)saleTicket{
while (1) {
NSLog(@"进行卖票-%@",[NSThread currentThread].name);
// @synchronized (锁对象),锁对象必须是一个,表示记录状态,一般用self就可以
@synchronized (self) {
NSInteger count = self.ticketCount;
if (count > 0 ){
self.ticketCount = count - 1;
NSLog(@"%@卖了一张票,还剩%ld张",[NSThread currentThread].name,(long)self.ticketCount);
}else{
NSLog(@"票卖完了");
break;
}
}
}
}
log: