iOS中的多线程(多线程的竞争)

641 阅读1分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

多线程的竞争

现象描述

在实际场景中,一块资源可能被多个线程共享,也就是说多个线程可能会访问同一个资源、同一个对象、同一个变量,在这种情况下容易引发数据错乱和数据安全问题(如下图)

Snip20211105_42.png

示例:

- (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: Snip20211105_46.png

问题解决

针对以上情况,通过线程锁来解决以上问题。当线程A去访问数据源之前,先将数据源锁住,读取数据并运算,将结果写入数据源之后,将其解锁。当线程B再去访问数据源之前,再次将数据源加锁,读取数据并运算,结果写入数据源之后再将其解锁。这样就避免了多个线程同时访问数据而造成数据错误问题(如下图)

Snip20211105_41.png

示例:

- (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:

Snip20211105_47.png