如何在Java中正确地创建一个线程安全的Singleton Factory?

10 java singleton factory-pattern

这是我第一次Factory上课.下面是我的Factory类,我不确定这是否是制作线程安全的Singleton Factory类的正确方法.我将使用这个工厂返回我客户的实例?

public class ClientFactory {

    private static ClientFactory instance = null;   

    private ClientFactory() {

    }

    public static ClientFactory getInstance() {

        if (instance == null)
        {
            instance =  new ClientFactory();
        }

        return instance;
    }

    public IClient getClient() {

        return new TestClient();
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的TestClient类 -

public class TestClient implements IClient {


}
Run Code Online (Sandbox Code Playgroud)

这就是我将如何使用我的工厂 -

IClient client = ClientFactory.getInstance().getClient();
Run Code Online (Sandbox Code Playgroud)

Jak*_*ski 23

实际上,您的工厂不是线程安全的,因为在竞争条件下,您可以在应用程序中使用多个ClientFactory.让我们假设两个线程:

  1. ThreadA正在评估条件'if(instance == null)'并且实例为null,因此它进入语句
  2. ThreadB正在评估条件'if(instance == null)'并且实例为null(因为A没有实例化它),所以它输入语句
  3. ThreadA创建新的ClientFactory()并返回它
  4. ThreadB创建新的ClientFactory()并返回它
  5. 现在我们在应用程序中有多个ClientFactory.当然,其他尝试稍后检索实例的线程将始终返回单个实例.

在我看来,在Java中编写单例的最简单方法是使用枚举.在你的情况下它将看起来:

public enum ClientFactory {
  INSTANCE;

  public Company getClient() {
    return new Company();
  }
}
Run Code Online (Sandbox Code Playgroud)

用法:

ClientFactory.INSTANCE.getClient()
Run Code Online (Sandbox Code Playgroud)


Bob*_*har 5

单例和工厂是不同的东西。要通过属性构造一个 Singleton,我想您可以将其 getInstance() 方法视为工厂。工厂制造“东西”。Singleton 意味着任何时候这些“事物”中只会有 0 个或正好 1 个存在。

如果您试图创建一个合适的单例,那么在 Java 中以线程安全的方式执行此操作会非常麻烦。如果没有同步或其他线程安全对策,上面列出的代码在初始化 ClientFactory 实例变量的检查然后设置代码周围有一个微妙的竞争条件。有两种方法可以解决这种竞争条件。您选择哪种方式很大程度上取决于通过 ClientFactory 构造函数的成本。我的构造函数通常是轻量级的,因此我选择了完全避免同步需求的方式。

public class ClientFactory {
    private static final ClientFactory instance = new ClientFactory();

    private ClientFactory() { }

    public static ClientFactory getInstance() {
        return instance;
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想在构造中“懒惰”,直到有人显式调用 getInstance() 才继续构建,那么现在需要同步以避免竞争条件。

public class ClientFactory {
    private static ClientFactory instance = null;

    private ClientFactory() { }

    public static synchronized ClientFactory getInstance() {
        if ( instance == null ) {
            instance = new ClientFactory();
        }
        return instance;
    }
}
Run Code Online (Sandbox Code Playgroud)


gsn*_*dev 5

Wiki上的线程安全实现(示例)-Wikipedia上的Singleton Pattern

就像上面的链接一样,单元素enum类型是为支持枚举的任何Java实现Singleton的最佳方法。

最好但最简单的方法之一:

public class ClientFactory{
    private ClientFactory() {}

    private static ClientFactory INSTANCE=null;

    public static ClientFactory getInstance() {
        if(INSTANCE==null){
            synchronize(ClientFactory.class){
                if(INSTANCE==null) // check again within synchronized block to guard for race condition
                    INSTANCE=new ClientFactory();
            }
        }
        return INSTANCE;
    }
}
Run Code Online (Sandbox Code Playgroud)

Source: 维基百科