iOS Swift多线程、互斥锁的实现方式

 Swift语言的多线程分为3种实现方式:

1、 Thread   ---  注意释放线程资源,API不健壮,慎用!

2、 Operation和OperationQueue --- 操作队列,可以并发执行多个也可以同时只执行1个。

3、Grand Central Dispatch(GCD)  --- 强烈推荐! 关键类DispatchQueue/DispatchGroup/DispatchWork

Item.


互斥锁也有多种实现方法:

1、 NSCondition 

2、 NSConditionLock  --- 比NSCondition多个条件方法

3、 NSRecursiveLock

4、 NSLock

5、 DispatchSemaphore  --- 参考GCD多线程详解

   前4个参考下图用法: 



        谈到多线程就要说生产者消费者模式, 下面以Thread为例实现该模式。

class ViewController: UIViewController {
    let lock = NSCondition()
    
    var count = 0    //生产者消费者模式
    let MAX_COUNT = 5   //仓库最多容量
    var thread1: Thread?   //特别提醒: 启动线程后要在适当时机释放!!!!!!
    var thread2: Thread?
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        thread1 = Thread(target: self, selector: #selector(product(sender:)), object: nil)
        thread2 = Thread(target: self, selector: #selector(consume(sender:)), object: nil)
        thread1?.start()
        thread2?.start()     //跟Java一样用start方法启动线程
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        if let running = thread1?.isExecuting, running {
            thread1?.cancel()     //只是修改状态位, 并没有真正停止! 需要再线程执行代码中添加判断。 作法同Java Thread
            print("设置线程1退出标识")
        }
        
        if let running = thread2?.isExecuting, running {
            thread2?.cancel()
            print("设置线程2退出标识")
        }

    }


    func product(sender: AnyObject) {
        repeat {
            //在线程执行体添加判断
            if let cancelled = thread1?.isCancelled, cancelled {
                print("真正关闭线程1")
                return   //调用cancel方法后, 退出线程执行体; 作用同Java的Thread一样
            }
            self?.lock.lock() ; defer { self?.lock.signal() ; self?.lock.unlock()}
            if count == MAX_COUNT {
                print("仓库已满了, 等待消费.......")
                lock.wait()
            }
            
            count += 1
            print("生产1个商品,当前总数:\(count)")
            
            lock.signal()    //只激活一个等待lock的线程, 而broadcast是激活所有等待lock的线程
            lock.unlock()
        } while true
    }
    
    func consume(sender: AnyObject) -> Void {
        while true {
            if let cancelled = thread2?.isCancelled, cancelled {
                print("真正关闭线程2")
                return   //调用cancel方法后, 退出线程执行体; 作用同Java的Thread一样
            }

            lock.lock()
            //Thread.sleep(forTimeInterval: 0.1)   //睡0.1秒
            
            if count == 0 {
                print("没有商品了,等待生产。。。。。。")
                lock.wait()   //没有商品了, 等待商品
            }
            count -= 1
            print("消费1个商品,当前总数:\(count)")

            lock.signal()
            lock.unlock()
        }

    }
}
     PS:    self?.lock.lock() ; defer { self?.lock.signal() ; self?.lock.unlock()} 注意这行代码的技巧, 如果想在函数退出时释放资源, 那么可以在申请资源的代码行后面跟着释放资源的语句, 这样更加直观明了。 Swift语句省略了分隔符";", 但是如果在一行里写多个表达式,可以用分号分隔。

       

Thread有2个实例化方法, 一个是Thread类的静态方法, 一个是上面代码中的对象方法。如果Thread的执行体是个死循环, 那么就要考虑关闭线程的问题; 解决方便就是在循环体头部添加判断条件, 在符合条件时退出循环。

      

Operation可以设置依赖关系控制执行顺序, Operation是个抽象类,必须继承它并实现其main方法。我们可以使用Opertion的派生类BlockOperation向OperationQueue添加任务,  且OperationQueue是线程安全的。

        

class ViewController: UIViewController {
    let lock = NSCondition()
    
    var count = 0    //生产者消费者模式
    let MAX_COUNT = 5   //仓库最多容量
    
    var queue:OperationQueue?
    var operation1: Operation?
    var operation2: Operation?
    
    override func viewDidLoad() {
        super.viewDidLoad()

        queue = OperationQueue()
        queue?.maxConcurrentOperationCount = 2  //最大并发数量, 设置1是就是单线程串行队列
        
        // Do any additional setup after loading the view.
        operation1 = BlockOperation(block: { [weak self] in
            //生产者
            while true {
                if let cancel = self?.operation1?.isCancelled, cancel {
                    print("生产者任务已结束")
                    return  //如果Operation被设置取消标志位则退出
                }
                
                self?.lock.lock()  //获取lock成功后程序继续向下执行, 否则继续等待
                //Thread.sleep(forTimeInterval: 0.1)   //睡0.1秒
                
                if self?.count == self?.MAX_COUNT {
                    print("仓库已满了, 等待消费.......")
                    self?.lock.wait()
                }
                
                self?.count += 1
                print("生产1个商品,当前总数:\(String(describing: self?.count))")
                
                self?.lock.signal()    //只激活一个等待lock的线程, 而broadcast是激活所有等待lock的线程
                self?.lock.unlock()
            }
        })
        
        operation2 = BlockOperation(block: { [weak self] in
            //消费者
            while true {
                if let cancel = self?.operation2?.isCancelled, cancel {
                    print("消费者任务已结束")
                    return
                }
                
                self?.lock.lock()
                //Thread.sleep(forTimeInterval: 0.1)   //睡0.1秒
                
                if self?.count == 0 {
                    print("没有商品了,等待生产。。。。。。")
                    self?.lock.wait()   //没有商品了, 等待商品
                }
                self?.count -= 1
                print("消费1个商品,当前总数:\(String(describing: self?.count))")
                
                self?.lock.signal()
                self?.lock.unlock()
            }
        })
        
        queue?.addOperation(operation1!)
        queue?.addOperation(operation2!)
        
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillAppear(animated)
        
        queue?.cancelAllOperations()   //设置operation的isCancelled标志位,并没有真正停掉Operation
    }

}
      从示例看出Operation的用法很简单, 跟DispatchQueue很像, 就是向Queue里扔个闭包就行了。 如果想要一个Operation在另一个Operation之前执行, 那么可以设置依赖关系。


      DispatchQueue的用法参考另一篇博客

http://blog.csdn.net/brycegao321/article/details/53898919


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值