Java 如何使用单例方法以更好的方式实现同步?
使用Java 如何使用单例方法以更好的方式实现同步?,java,multithreading,synchronization,thread-safety,singleton,Java,Multithreading,Synchronization,Thread Safety,Singleton,使用单例模式实现的类如下所示,当多个线程访问此方法时,只有一个线程必须创建实例,所以我所做的就是同步该方法 private static synchronized FactoryAPI getIOInstance(){ if(factoryAPI == null){ FileUtils.initWrapperProp(); factoryAPI = new FactoryAPIImpl(); } return factoryAPI; }
单例模式实现的类如下所示,当多个线程访问此方法时,只有一个线程必须创建实例,所以我所做的就是同步该方法
private static synchronized FactoryAPI getIOInstance(){
if(factoryAPI == null){
FileUtils.initWrapperProp();
factoryAPI = new FactoryAPIImpl();
}
return factoryAPI;
}
我觉得这是不必要的,因为只有在第一次创建实例时,才会返回已经创建的实例。将synchronized
添加到块时,一次只允许一个线程访问该方法
getIOInstance
执行两项任务
i) 初始化属性和
ii)首次创建新实例
因此,我尝试在这里执行块级同步
,如下所示
private static FactoryAPI getIOInstance(){
if(factoryAPI == null){
synchronised {
if(factoryAPI == null){
FileUtils.initWrapperProp();
factoryAPI = new FactoryAPIImpl();
}
}
}
return factoryAPI;
}
我宁愿第二个是正确的。我用得对吗?欢迎任何建议。使用第一种方法,因为第二种方法不是线程安全的
当你说
factoryAPI = new FactoryAPIImpl();
编译器可以按照以下顺序自由执行代码:
1) 在堆上分配一些内存
2) 将factoryAPI初始化为该分配空间的地址
3) 调用FactoryAPIImpl的构造函数
问题是当另一个线程在步骤2之后和步骤3之前调用getIOInstance()时。它可能会看到指向未初始化factoryAPI实例的非空factoryAPI变量。此问题有许多不同的答案,例如,您可以在上找到广泛的讨论
现代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
的所有后续并发调用都将返回正确初始化的实例
,而不会产生任何额外的同步开销。通过使字段
易变可以避免可见性问题。重复:在下面的链接中找到解决方案:第二个方法被调用,并且只有在遵循精确公式的情况下才能正确工作。把它当作一个更安全的替代品。听起来好像OP是在寻找一个懒散的加载单体。