iOS 多线程安全之产生原因

在 iOS 中我们经常需要使用到 多线程 ,那么多线程 使用中有个问题 需要注意就是 多线程访问数据的安全。我们举例说明

现在 controller 中有两个属性。 对每个属性 我们分别使3个多线程 去读写 这两个属性

/*

 nonatomic  setter getter 都不加锁

 */

@property (nonatomic,assign) NSInteger leftTicketsCount;


/**

 使用atomic多线程原子性控制,atomic的原理给setter加上锁,getter不会加锁

 */

@property (atomic,assign) NSInteger newLefTicketsCount;


代码如下

#pragma mark ---- Thread fighting over shampo

/**

 多线程 争抢 资源  atomic  所谓争抢 就是几乎 同时访问的意思

 */

- (void)fightingOverShampo

{

    self.leftTicketsCount=10;

    

    //开启多个线程,模拟售票员售票

    self.thread1=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];

    self.thread1.name=@"售票员1";

    self.thread2=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];

    self.thread2.name=@"售票员2";

    self.thread3=[[NSThread alloc]initWithTarget:self selector:@selector(sellTickets) object:nil];

    self.thread3.name=@"售票员3";

    

    [self.thread1 start];

    [self.thread2 start];

    [self.thread3 start];


}


- (void)sellTickets

{

    while (true) {

        // 从代码来看应该 应该不可能出现 负数的 票数

//        NSLog(@"start ticket %ld---",(long)self.leftTicketsCount);

        if (self.leftTicketsCount>0) { // 读取

            

            NSLog(@"valid ticke %ld",self.leftTicketsCount);

            [NSThread sleepForTimeInterval:1]; // 这句话 是关键 睡眠 执行 笔者认为 如果

            self.leftTicketsCount--;

            NSLog(@"thread:%@ ----> %ld",[[NSThread currentThread] name],self.leftTicketsCount);

        }else{

           

            NSLog(@"break thread:%@ ----> %ld",[[NSThread currentThread] name],self.leftTicketsCount);

            break;

        }

    

    }

}



#pragma mark ---- 第二个 属性 对比 

- (void)fightingOverShampoTwo

{

    self.newLefTicketsCount=10;

    

    //开启多个线程,模拟售票员售票

    self.thread4=[[NSThread alloc]initWithTarget:self selector:@selector(atomicSellTicket) object:nil];

    self.thread4.name=@"售票员4";

    

    self.thread5=[[NSThread alloc]initWithTarget:self selector:@selector(atomicSellTicket) object:nil];

    self.thread5.name=@"售票员5";

    

    self.thread6=[[NSThread alloc]initWithTarget:self selector:@selector(atomicSellTicket) object:nil];

    self.thread6.name=@"售票员6";

    

    [self.thread4 start];

    [self.thread5 start];

    [self.thread6 start];

}



- (void)atomicSellTicket

{

    while (true) {

        // 从代码来看应该 应该不可能出现 负数的 票数

        //        NSLog(@"start ticket %ld---",(long)self.leftTicketsCount);

        if (self.newLefTicketsCount>0) { // 读取

            

//            NSLog(@"valid ticke %ld",self.newLefTicketsCount);

            [NSThread sleepForTimeInterval:1]; // 这句话 是关键 睡眠 执行 笔者认为 如果

            self.newLefTicketsCount--;

            NSLog(@"new  thread:%@ ----> %ld",[[NSThread currentThread] name],self.newLefTicketsCount);

        }else{

            

//            NSLog(@"break thread:%@ ----> %ld",[[NSThread currentThread] name],self.leftTicketsCount);

            break;

        }

        

    }

}


结果若下:


我们发现 居然出现了 票数 为 负数的情况!!!!! 

如果我们把  [NSThread sleepForTimeInterval:1]; 这句话去掉 再次运行 就不会必然出现这种情况了。

这句话的作用是 我们人为的造成 争抢资源就是 多线程 同时访问 某个变量的 场景 。就好像大家都在同时按键盘抢票。 这个时候 数据是不正常的。不论我们 设置 属性是 atomic 还是 nonatomic 都会出现。

再次 假设 我们把 [NSThread sleepForTimeInterval:1] 替换上一个 耗时的代码 比如:

            for (int i=0; i<1000;i++ ) {

                for (int j=0; j<1000; j++) {

                    m++;

                }

            }


依然 出现 票数为 负数的情况  。  在多线程编程中, 很多开发者 很容易编写这样消耗时间的操作,过后很容易出现 数据 不正常的情况。





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值