How to correctly make a thread safe Singleton Factory in Java? [duplicate]

牧云@^-^@ 提交于 2019-12-03 06:12:31

In fact your factory isn't thread safe, because in race condition you can have more than one ClientFactory living in application. Lets assume two threads:

  1. ThreadA is evaluating condition 'if (instance == null)' and instance is null, so it enters statement
  2. ThreadB is evaluating condition 'if (instance == null)' and instance is null (because A didn't make to instantiate it), so it enters statement
  3. ThreadA creates new ClientFactory() and returns it
  4. ThreadB creates new ClientFactory() and returns it
  5. Now we have more than one ClientFactory in application. Of course other threads trying to retrieve instance some time later will always return single instance.

In my opinion the easiest way to write singleton in Java is to use enum. In your case it will looks:

public enum ClientFactory {
  INSTANCE;

  public Company getClient() {
    return new Company();
  }
}

And usage:

ClientFactory.INSTANCE.getClient()

Thread safe implementations(examples) on Wiki - Singleton Pattern on Wikipedia

As in the link above, a single-element enum type is the best way to implement a Singleton for any Java that supports enums.

One of the best yet simple ones:

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

Source: Wikipedia

Singletons and Factories are different things. To property construct a Singleton, I guess you could think of its getInstance() method as a factory. Factories make "things". Singleton means that there will only ever be 0 or exactly 1 of these "things" in existence at any time.

If you are trying to make a proper Singleton, it is surprisingly cumbersome to do this in a Thread-safe manner in Java. Without synchronization or other thread-safe countermeasures, the code you list above has a subtle race-condition around the check-then-set code to initialize ClientFactory instance variable. There are two ways around this race-condition. Which way you pick is largely gated by how expensive it is to go through the ClientFactory constructor. My constructors are typically lightweight, so I go the path of avoiding the need for synchronization all together.

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

    private ClientFactory() { }

    public static ClientFactory getInstance() {
        return instance;
    }
}

If you want to be "lazy" in the construction, not building on until someone explicitly calls getInstance(), now synchronization is needed to avoid the race condition.

public class ClientFactory {
    private static ClientFactory instance = null;

    private ClientFactory() { }

    public static synchronized ClientFactory getInstance() {
        if ( instance == null ) {
            instance = new ClientFactory();
        }
        return instance;
    }
}

Your factory is a perfect Singleton (it is just that it is not thread-safe).

the ClientFactory is a factory,but neither a Singleton Factory,nor a thread-safe factory. At any point,when ClientFactory.getInstance().getClinet() is invoked,it will return a new instance,so it is not absolutely a Singleton Factory.If we fix the method like this

private IClient iclient;

public IClient getClient() {

    if ( iclient == null ){
         iclient = new TestClient();
    }

    return iclient ;
}

Then the factory is a singleton factory,but it is not thread-safe. Assume if there are more than one threads invoke getInstance,all of the threads will find that the client factory instance is null,so they will construct the instance respectively, and the problem is the same with the method getClient().

It is very easy to fix it,you can declare these two method as synchronized.

First of all,if you really want to use factory parrtern,don't forget to hidden the client's Constructor

private TestClient(){
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!