我在
Swift 3中创建了一个简单的单例:
class MySingleton { private var myName: String private init() {} static let shared = MySingleton() func setName(_ name: String) { myName = name } func getName() -> String { return myName } }
由于我使init()私有,并且声明的共享实例是静态let,我认为初始化器是线程安全的.但是myName的getter和setter函数呢,它们是否安全?
解决方法
你写的那些获取者不是线程安全的,你是对的.在Swift中,目前实现此目的的最简单(读取最安全)方法是使用Grand Central Dispatch队列作为锁定机制.最简单(也是最容易推理)的方法是使用基本的串行队列.
class MySingleton { static let shared = MySingleton() // Serial dispatch queue private let lockQueue = DispatchQueue(label: "MySingleton.lockQueue") private var _name: String var name: String { get { return lockQueue.sync { return _name } } set { lockQueue.sync { _name = newValue } } } private init() { _name = "initial name" } }
使用串行调度队列将保证先进先出执行以及实现对数据的“锁定”.也就是说,在更改数据时无法读取数据.在这种方法中,我们使用sync来执行实际的数据读写,这意味着调用者总是被迫等待轮到其他类似于其他锁定原语.
注意:这不是most performant方法,但它易于阅读和理解.它是一种很好的通用解决方案,可以避免竞争条件,但并不意味着为并行算法开发提供同步.
资料来源:
https://mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html
What is the Swift equivalent to Objective-C’s “@synchronized”?