如何通过单例方法以更好的方式实现同步?



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;
}

我更喜欢第二个是正确的。我以正确的方式使用它吗?欢迎任何建议。

使用第一种方法,因为第二种方法不是线程安全的。

当你说,

factoryAPI = new FactoryAPIImpl();

编译器可以按以下顺序自由执行代码:

1( 在堆
上分配一些内存 2( 将工厂 API 初始化为该分配空间
的地址 3( 调用 FactoryAPI 的构造函数

问题是当另一个线程在步骤 2 之后和步骤 3 之前调用 getIOInstance(( 时。它可能会看到指向未初始化的工厂 API 实例的非空工厂 API 变量。

这个问题有许多不同的答案,例如,您可以在SEI上找到广泛的讨论。

现代Java解决方案很简单:使用枚举 - 因为JLS保证编译器/JVM将只创建一件事

发现按需初始化持有者初始化方法,该方法初始化为一个有趣的方法,如下所示,

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,而不会产生任何额外的同步开销。

相关内容

  • 没有找到相关文章

最新更新