我在 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()
private ,并且还声明shared
实例为static let
,我认为初始化器是线程安全的。但是 getter 和 setter 函数呢?myName
,它们线程安全吗?
一种稍微不同的方法(来自 Xcode 9 Playground)是使用并发队列而不是串行队列。
final class MySingleton {
static let shared = MySingleton()
private let nameQueue = DispatchQueue(label: "name.accessor", qos: .default, attributes: .concurrent)
private var _name = "Initial name"
private init() {}
var name: String {
get {
var name = ""
nameQueue.sync {
name = _name
}
return name
}
set {
nameQueue.async(flags: .barrier) {
self._name = newValue
}
}
}
}
- 使用并发队列意味着来自多个线程的多个读取不会互相阻塞。由于获取时没有突变,因此可以同时读取该值,因为......
- 我们正在使用设置新值
.barrier
异步调度。该块可以异步执行,因为调用者无需等待值被设置。该块将不会运行,直到它前面的并发队列中的所有其他块都完成为止。因此,当此 setter 等待运行时,现有的挂起读取不会受到影响。屏障意味着当它开始运行时,不会有其他块运行。实际上,在 setter 的持续时间内将队列转变为串行队列。在该块完成之前不能进行进一步的读取。当块完成时,新值已被设置,在此设置器之后添加的任何获取器现在可以同时运行。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)