美文网首页
多线程安全隐患

多线程安全隐患

作者: 极客汤米 | 来源:发表于2015-10-26 09:53 被阅读154次

因为还是喜欢简书的界面和简洁的markdown书写方式,所以把以前写的文章从博客园迁移过来,如果大家以前看过,谢谢大家持久以来的关注,还会陆续更新很多iOS学习文章及其笔记。

本文要点

  • 多线程安全隐患引出
  • 多线程安全隐患代码示例
  • 多线程安全隐患解决方案

一、多线程安全隐患引出

假设火车站有3个卖票窗口,余票是1000,卖票窗口3个线程同一时刻读取剩余票数,都是读取的1000,卖票线程1卖了一张 ,余票变成999。卖票线程2反应慢点,在卖票线程1后面执行卖票,因为卖票线程2刚开始读取的余票也是1000,所以在卖掉一张后,余额也变成999。卖票线程3反应更慢,在卖票线程2后面执行卖票,因为卖票线程3刚开始读取的余票也是1000,所以在卖掉一张后,余额依旧也变成999。所以出现了错误,本来卖了3张,可是余票还有999张。

因此当多个线程访问同一块资源时(同一个对象、同一个变量、同一个文件),很容易引发数据错乱和数据安全问题。

二、多线程安全隐患代码示例

1>声明3个卖票线程,以及 leftTicketCount 来保存余票数

@property (nonatomic, strong) NSThread *thread1; //线程1 
@property (nonatomic, strong) NSThread *thread2; //线程2
@property (nonatomic, strong) NSThread *thread3; //线程3 
@property (nonatomic, assign) int leftTicketCount; //剩余票数

2>在viewDidLoad里面,设置余票为50张票,并创建了3个线程,并且分别起名“1号窗口”,“2号窗口” 及 “3号窗口”

self.leftTicketCount = 50;
self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread1.name = @"1号窗⼝口";

self.thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil];
self.thread2.name = @"2号窗⼝口";

self.thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket) object:nil]; 
self.thread3.name = @"3号窗⼝口";

3>实现售票方法

- (void)saleTicket {
    while (1) {
      int count = self.leftTicketCount; 
      if (count > 0) { 
        //线程睡⼀一下,其他线程才能有机可乘
        [NSThread sleepForTimeInterval:0.05];
        self.leftTicketCount = count - 1;
        NSLog(@"%@卖了⼀一张票, 剩余%d张票", [NSThread currentThread].name, self.leftTicketCount); 
         }else {
          return; // 退出循环 
        }
    } 
}

输出结果为:

输出结果

从结果可以轻易看出多个线程访问并操作剩余票数的时候,引发了数据错乱和数据安全问题

三、多线程安全隐患解决方案

在线程A读取数据后,加一把锁,别的线程就不能访问了,只允许加锁的线程A访问。当这个加锁线程操作完数据后,线程A解锁,此时别的线程就能访问了, 假设轮到线程B访问,线程B也先加把锁,保证只有自己能访问,执行完操作再解锁....就这样循环往复,只要谁访问就加把锁,直到操作结束后再解锁。这就是互斥锁。

加锁的目的就是为了保证同一时间,只能一个线程访问并执行代码。

代码实现互斥锁

- (void)saleTicket {
    while (1) {
        // ()⼩小括号⾥里⾯面放的是锁对象 
        @synchronized(self) { // 开始加锁
          int count = self.leftTicketCount; 
         if (count > 0) {
             [NSThread sleepForTimeInterval:0.05];
             self.leftTicketCount = count - 1;
             NSLog(@"%@卖了⼀一张票, 剩余%d张票", [NSThread currentThread].name, self.leftTicketCount); 
      } else {
        return; // 退出循环 
      }
    } // 解锁 
  }
}   

通过把自身当做锁对象进行加锁,保证了自己在访问操作数据的时候,别的线程没法进来,只有等待执行完后开锁。

注意

1.@synchronized(self) 不能写在 while (1)前面,尽管打印结果正确,但是始终执行的只有最先进来的进程。
2.尽管互斥锁能够有效防止因多线程抢夺资源而造成的数据安全问题,但是其需要消耗大量的CPU资源。
3.而且只有再多条线程抢夺同一块资源的时候才使用互斥锁

联系方式

如果你喜欢这篇文章,可以继续关注我,微博:极客汤米,欢迎交流。

相关文章

  • 多线程 线程安全

    多线程的安全隐患 我们用多线程有很多好处,但是也存在安全隐患资源共享1块资源可能会被多个线程共享,也就是多个线程可...

  • iOS底层原理总结 - 多线程的锁

    目录:1.为什么要线程安全2.多线程安全隐患分析3.多线程安全隐患的解决方案4.锁的分类-13种锁4.1.1OSS...

  • iOS-多线程2-线程安全、OSSpinLock

    一. 安全隐患 利用多线程异步可以同时做不同的事情,效率更高,但是这样也会有安全隐患。 造成安全隐患的原因:一块资...

  • 多线程(三)

    上篇多线程(二)我们看了多线程的死锁和队列组的使用,下面我们再来看看多线程的安全隐患代码详见 gitHub_De...

  • NSThread多线程实现

    1. 创建和启动线程 2. 控制线程状态 3. 多线程的安全隐患 4. 安全隐患解决 – 互斥锁 5. 原子和非原...

  • iOS_线程安全

    多线程的安全隐患 当多个线程访问同一块资源时,很容易引发数据错乱和数据安全问题 安全隐患解决 方案一:使用“同步块...

  • 多线程安全隐患

    因为还是喜欢简书的界面和简洁的markdown书写方式,所以把以前写的文章从博客园迁移过来,如果大家以前看过,谢谢...

  • 4.多线程基础(四) 线程的状态,安全性

    1.线程的状态 2.多线程的安全隐患 3.多线程的同步问题 //没有加锁之前 //加锁之后: 下面不是唯一的: 4...

  • 多线程(四)

    上篇多线程(三)我们看了多线程的安全隐患 以及各种锁的简单使用,接下来我们来看看锁的比较、以及自旋锁、互斥锁比较 ...

  • iOS多线程-线程安全

    复习下线程的基础知识, 这里主要是参考文顶顶多线程篇复习写的。 一、多线程的安全隐患 资源共享1块资源可能会被多个...

网友评论

      本文标题:多线程安全隐患

      本文链接:https://www.haomeiwen.com/subject/kvkxhttx.html