为何Code A的双重检查锁实现无法返回Singleton实例?
为什么两种双重检查锁定实现的单例在Compose中表现不同?
我原本认为Code A与Code B的实现等价,通过调用preferenceParState: PreferenceParameterState = rememberPreferenceParameterState()都能返回单例实例。但通过preferenceParState.hashCode()测试发现,Code B可以返回单例,Code A却不行,另外测试发现Code A中不同实例的mContext.hashCode()值是相同的。
Code A
class PreferenceParameterState private constructor(context: Context) { companion object { @Volatile private var instance: PreferenceParameterState? = null fun getInsance(context: Context): PreferenceParameterState{ return instance ?: synchronized(this) { instance ?: PreferenceParameterState(context) } } } } @Composable fun rememberPreferenceParameterState(): PreferenceParameterState { val mContext= LocalContext.current return remember { PreferenceParameterState.getInsance(mContext) } }
Code B
class PreferenceParameterState private constructor(context: Context) { companion object { @Volatile private var instance: PreferenceParameterState? = null fun getInsance(context: Context): PreferenceParameterState{ if (instance == null) { synchronized(this) { if (instance == null) { instance = PreferenceParameterState(context) } } } return instance!! } } } @Composable fun rememberPreferenceParameterState(): PreferenceParameterState { val mContext= LocalContext.current return remember { PreferenceParameterState.getInsance(mContext) } }
问题原因分析
核心差异在于双重检查锁定中是否对单例变量完成赋值:
- Code A的致命漏洞:同步块内的
instance ?: PreferenceParameterState(context)只是创建了新实例,但并没有将这个实例赋值给companion object中的instance变量。也就是说,每次调用getInsance时,只要外层的instance还是null,就会进入同步块创建新实例,但instance变量始终保持null,导致后续调用会重复创建新对象,自然无法实现单例。 - Code B的正确实现:同步块内明确执行了
instance = PreferenceParameterState(context),将新建的实例引用赋值给instance变量。后续调用getInsance时,外层检查会发现instance不为null,直接返回已有实例,实现了单例效果。
至于Code A中不同实例的mContext.hashCode()相同,是因为LocalContext.current在同一Compose环境下返回的是同一个Context实例(通常是Application Context或当前Activity的Context),所以即使PreferenceParameterState被多次创建,它们持有的Context引用是同一个,因此hashCode一致。
内容的提问来源于stack exchange,提问作者HelloCW
相关产品推荐
相关产品推荐

