多线程(二)线程的安全隐患
有了多线程就有了资源竞争,当多个线程对同一资源进行操作时就容易出现安全隐患。
下面举一个卖票的例子来说明线程的安全隐患
@interface ViewController ()
@property (assign, nonatomic)NSInteger tickets;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//设置票的数量为5
_tickets = 5;
//线程一
NSThread *threadOne = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
threadOne.name = @"threadOne";
//线程二
NSThread *threadTwo = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
//开启线程
[threadOne start];
[threadTwo start];
}
- (void)saleTickets
{
while (1)
{
[NSThread sleepForTimeInterval:1];
if (_tickets > 0)
{
_tickets--;
NSLog(@"剩余票数= %ld",_tickets);
}
else
{
NSLog(@"票卖完了");
break;
}
}
}
打印结果
可以看到票的余量是很混乱的,看下面一张图可以比较清楚的了解为什么会出现这种情况

如何解决?添加互斥锁(当A线程对数据进行操作时(加锁),线程B不能访问当前数据,直到A对数据完成读写操作结束(解锁),线程B才能对数据进行操作)
这样就保证了数据的安全性;
下面是代码
@interface ViewController ()
@property (assign, nonatomic)NSInteger tickets;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//设置票的数量为5
_tickets = 5;
//线程一
NSThread *threadOne = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
threadOne.name = @"threadOne";
//线程二
NSThread *threadTwo = [[NSThread alloc] initWithTarget:self selector:@selector(saleTickets) object:nil];
//开启线程
[threadOne start];
[threadTwo start];
}
- (void)saleTickets
{
while (1)
{
@synchronized(self) {
[NSThread sleepForTimeInterval:1];
if (_tickets > 0)
{
_tickets--;
NSLog(@"剩余票数= %ld",_tickets);
}
else
{
NSLog(@"票卖完了");
break;
}
}
}
}
打印结果,可以看到数据正常了;

关于代码中用到的@synchronized,它是一个互斥锁,锁的概念将在下一篇中详细讲解
浙公网安备 33010602011771号