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