美文网首页
使用队列实现线程同步

使用队列实现线程同步

作者: 来金德瑞 | 来源:发表于2021-03-16 11:09 被阅读0次
  • 多个线程访问同一块资源时候,容易引发数据错乱与数据安全问题
  • 使用GCD中的串行队列,是实现线程同步的一个常规方案,并且效率也不低

资源竞争的案例

    // 起初有50块钱
    private var money = 50
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        /// 存钱取钱测试代码
        moneyTest()
    }
    
    
    /// 多线程竞争money这个资源
    func moneyTest() {
        DispatchQueue.global().async {
            for _ in 0...10 {
                self.saveMoney()
            }
        }
        
        DispatchQueue.global().async {
            for _ in 0...10 {
                self.drawMoney()
            }
        }
    }

    
    /// 存钱
    private func saveMoney() {
        var oldMoney = self.money
        sleep(1)
        oldMoney = oldMoney + 50
        self.money = oldMoney
        print("存50,还剩余\(oldMoney) - \(Thread.current)")
    }
    
    /// 取钱
    private func drawMoney() {
        var oldMoney = self.money
        sleep(1)
        oldMoney = oldMoney - 20
        self.money = oldMoney
        print("取20,还剩余\(oldMoney) - \(Thread.current)")
    }

竞争导致的后果

取20,还剩余0 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余100 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余50 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余150 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余0 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余200 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余-50 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余250 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余-100 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余300 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余-150 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余350 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余-200 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余400 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余-250 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余450 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余-300 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余500 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余-350 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余550 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}
取20,还剩余-400 - <NSThread: 0x60000300b400>{number = 6, name = (null)}
存50,还剩余600 - <NSThread: 0x6000030461c0>{number = 7, name = (null)}

如何解决该问题

    // 起初有50块钱
    private var money = 50
    
    // 创建一个串行队列
    private let queue = DispatchQueue(label: "com.nsl.serialQueue")
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        /// 存钱取钱测试代码
        moneyTest()
    }
    
    /// 多线程竞争money这个资源
    func moneyTest() {
        DispatchQueue.global().async {
            for _ in 0...10 {
                self.saveMoney()
            }
        }
        
        DispatchQueue.global().async {
            for _ in 0...10 {
                self.drawMoney()
            }
        }
    }

    /// 存钱
    private func saveMoney() {
        // 串行 + 同步
        self.queue.sync {
            var oldMoney = self.money
            sleep(1)
            oldMoney = oldMoney + 50
            self.money = oldMoney
            print("存50,还剩余\(oldMoney) - \(Thread.current)")
        }
  
    }
    
    /// 取钱
    private func drawMoney() {
        // 串行 + 同步
        self.queue.sync {
            var oldMoney = self.money
            sleep(1)
            oldMoney = oldMoney - 20
            self.money = oldMoney
            print("取20,还剩余\(oldMoney) - \(Thread.current)")
        }
    }

解决问题后的输出

取20,还剩余30 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余80 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余60 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余110 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余90 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余140 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余120 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余170 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余150 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余200 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余180 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余230 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余210 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余260 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余240 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余290 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余270 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余320 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余300 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余350 - <NSThread: 0x60000122e780>{number = 7, name = (null)}
取20,还剩余330 - <NSThread: 0x600001222740>{number = 6, name = (null)}
存50,还剩余380 - <NSThread: 0x60000122e780>{number = 7, name = (null)}

相关文章

  • 使用队列实现线程同步

    多个线程访问同一块资源时候,容易引发数据错乱与数据安全问题 使用GCD中的串行队列,是实现线程同步的一个常规方案,...

  • 队列

    队列: 先进先出 栈: 先进后出 1.使用Queue实现生产者与消费者解耦 可以使用队列来实现线程间的同步 生产者...

  • Swift队列和线程的搭配执行

    队列分为 串行队列,并行队列,特殊的主队列线程分为 同步线程,异步线程 搭配结果一共6种情况1:主队列,同步线程。...

  • GCD

    1、同步串行队列 2、同步并行队列 3、异步串行队列 4、异步并行队列 5、死锁 主线程中创建同步串行队列 主线程...

  • GCD多线程—串行、并行、同步、异步线程数目

    一、串行队列 1、同步运行 结论:串行队列-同步运行,不会开启新的线程,线程函数会在创建队列所在的线程中执行(如上...

  • 线程池

    一、引言 二、py同步原语 三、实现线程安全的队列Queue 队列可能会被【多个线程】同时操作,所以一定要保证【线...

  • ios线程概念运用

    GCD 整个使用的格式为: 先确定要创建的队列: (串行 并行) 队列中该线程是同步还是异步执行线程() 执行...

  • GCD线程之间的通信

    通过线程的依赖关系实现线程同步: 组队列(dispatch_group_t) 阻塞任务(dispatch_barr...

  • GCD 细细的读

    目录 前言 为什么选择GCD? 串行队列、并行队列、同步、异步 线程死锁解析 DispatchQueue的使用 D...

  • 线程锁

    探讨iOS开发中各种锁使用NSCondition实现多线程同步 NSCondition是线程同步, 阻塞线程。 取...

网友评论

      本文标题:使用队列实现线程同步

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