使用Singleton Pattern
实现的类如下所示,当多个线程访问此方法时,只有一个线程必须创建实例,所以我所做的就是同步方法
private static synchronized FactoryAPI getIOInstance(){
if(factoryAPI == null){
FileUtils.initWrapperProp();
factoryAPI = new FactoryAPIImpl();
}
return factoryAPI;
}
我觉得这是不必要的,因为只有第一次创建实例时,其余时间才会返回已创建的实例。将synchronised
添加到块时,一次只允许一个线程访问该方法。
getIOInstance
执行两项工作
i)初始化属性和
ii)第一次创建新实例
所以,我尝试在此处阻止级别synchronisation
,如下所示
private static FactoryAPI getIOInstance(){
if(factoryAPI == null){
synchronised {
if(factoryAPI == null){
FileUtils.initWrapperProp();
factoryAPI = new FactoryAPIImpl();
}
}
}
return factoryAPI;
}
我更喜欢第二个是正确的。我是以正确的方式使用它吗?欢迎任何建议。
答案 0 :(得分:1)
使用第一种方法,因为第二种方法不是线程安全的。
当你说,
factoryAPI = new FactoryAPIImpl();
编译器可以按以下顺序自由执行代码:
1)在堆上分配一些内存
2)将factoryAPI初始化为该分配空间的地址
3)调用FactoryAPIImpl的构造函数
问题是当另一个线程在步骤2之后和步骤3之前调用getIOInstance()时。它可能会看到一个指向未初始化的FactoryAPI实例的非null factoryAPI变量。
答案 1 :(得分:0)
答案 2 :(得分:0)
发现Initialization-on-demand holder初始化方法是一个有趣的方法,如下所示,
public class FactoryAPI {
private FactoryAPI() {}
private static class LazyHolder {
static final Something INSTANCE = new Something();
}
public static Something getInstance() {
return FactoryAPI.INSTANCE;
}
}
由于JLS保证类初始化阶段是串行的,即非并发的,因此在加载和初始化期间静态getInstance方法不需要进一步的同步。
由于初始化阶段在一个串行操作中写入静态变量INSTANCE
,getInstance
的所有后续并发调用将返回相同的正确初始化INSTANCE
,而不会产生任何额外的同步开销。