Pergunta

When need a singleton, is a static field a elegant solution?

class HelperSingleton {
  static Helper singleton = new Helper();

  public static Helper getInstance() {
       return singleton;
     }
  }

When two threads access to getInstance at the same time, is there a chance the field singleton is not initialized completely? Or see the default values for fields of the helper object, rather than the values set in the constructor? Static singleton is also lazy initialization?

I mean, static Helper singleton = new Helper(); is this assigment atomic? And won't return default values ?

Foi útil?

Solução

1) When a thread accesses static getInstance the first time class loader has to load the HelperSingleton class and it will lock other thread before class is loaded. So there is an implicit synchronization present. J.Bloch "Effective Java" Item 71 modern VM will synchronize field access only to initialize the class. Once the class is initialized, the VM will patch the code so that subsequent access to the field does not involve any testing or synchronization.

2) Your singleon is lazy, because there is only one access point - getInstance. Not only instance is created on demand but the whole class is loaded on demand. A class will not be initialized until it is used [JLS, 12.4.1].

Outras dicas

I think that the most elegant solution for a singleton is this:

public enum Singleton {

    INSTANCE;

    public Singleton getInstance() {
        return INSTANCE;
    }
}

Using the singleton pattern is somewhat problematic because sometimes you don't know that you really only have just one of them. Consider the case for example when you are using class loaders.

This question (and others) has a thorough explanation by the way.

Take a look at http://en.wikipedia.org/wiki/Singleton_pattern

There are a number of styles available explaining the good/bad.

If it were this :

class HelperSingleton {
  static Helper singleton = null;
  public static Helper getInstance() {
      if(singleton == null) {
         singleton = new Helper();
      }
      return singleton;
    }
}

There could be a possibility here :

  1. Thread 1 calls the getInstance() method and determines that singleton is null.

  2. Thread 1 enters the if block, but is preempted by Thread 2 before creating a new instance.

  3. Thread 2 calls the getInstance() method and determines that instance is null.

  4. Thread 2 enters the if block and creates a new Helper object and assigns the variable singleton to this new object.

  5. Thread 2 returns the Singleton object reference.

  6. Thread 2 is preempted by Thread 1.

  7. Thread 1 starts where it left off and executessingleton = new Helper(); which results in another Singleton object being created.

  8. Thread 1 returns this object.

So we end up with two instances. Best way to create Singletons are using enum as answered here.

static Helper singleton = new Helper(); 

Here a new instance of Helper is created when the class is loaded and singleton holds the reference to that instance. You can get the detailed initialization process in JLS 12.4.2.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top