我一直在查看一些Google示例代码,他们似乎使用以下代码创建单例:
companion object {
// For Singleton instantiation
@Volatile
private var instance: CarRepository? = null
fun getInstance(carDao: CarDao) =
instance ?: synchronized(this) {
instance ?: CarRepository(carDao).also { instance = it }
}
}
Run Code Online (Sandbox Code Playgroud)
所以我知道这@Volatile意味着
将带注释的属性的JVM支持字段标记为volatile,这意味着对此字段的写入会立即对其他线程可见.
是否所有单身实例都应标记为@Volatile?如果是这样,为什么?
最后,我不明白这个getInstance功能
instance ?: synchronized(this) {
instance ?: CarRepository(carDao).also { instance = it }
}
Run Code Online (Sandbox Code Playgroud)
这到底是做什么的?
更新:来源:谷歌的向日葵
我改变了我自己使用的Repository和Dao名称,但它在Repository文件中是相同的逻辑.
有一个伟大的答案在这里为什么领域应该是震荡。本质上,没有它,一个线程可能会在实例完全构建之前获得对该实例的引用。
对于该getInstance()功能,您具有:
instance ?:
Run Code Online (Sandbox Code Playgroud)
这意味着如果该方法instance不为null,则将返回,否则将执行的右侧?:。
synchronized(this) {
instance ?:
}
Run Code Online (Sandbox Code Playgroud)
同样在这里,在第一次检查实例是否为null之后,在类(companion object)上同步之后,它再次检查非null值,并在执行最后一个命令之前将其返回(如果可用):
CarRepository(carDao).also { instance = it }
Run Code Online (Sandbox Code Playgroud)
这将初始化一个新变量CarRepository,然后使用该.also块,在返回之前将it(CarRepository)分配给该instance字段。仅仅因为整个语句是一个表达式,这有点令人困惑。如果使它更加详细,则可能看起来像:
fun getInstance(carDao: CarDao): CarRepository {
var cachedInstance = instance
if (cachedInstance != null) {
return cachedInstance
}
synchronized(this) {
cachedInstance = instance
if (cachedInstance == null) {
cachedInstance = CarRepository(carDao)
instance = cachedInstance
}
return cachedInstance
}
}
Run Code Online (Sandbox Code Playgroud)
值得一提的是,我并不真的相信这个特定的例子是一个很好的模式。例如,考虑以下内容:
val carDao1 = CarDaoImpl1()
val carDao2 = CarDaoImpl2()
val carRepo1 = CarRepository.getInstance(carDao1)
val carRepo2 = CarRepository.getInstance(carDao2)
// carRepo2 actually points to carDao1!
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
546 次 |
| 最近记录: |