How to apply the Singleton pattern correctly?

The Class PEHandlerService needs to have a single instance and I don't want to use synchronized because of the slowness, I worked out the following code:

public class PEHandlerService extends PlanilhaHandler {
    private LanguageHandler languageHandler;
    private static PEHandlerService instancia = new PEHandlerService();

    private PEHandlerService() {
        this.languageHandler = new LanguageHandler();
    }

    public static PEHandlerService getInstancia() {
        return instancia;
    }
}

I get java.lang.NullPointerException after I instantiate and access the methods, I tried instantiating PEHandlerService in the private constructor and the same occurs.

I can only when I change to:

public class PEHandlerService extends PlanilhaHandler {
    private LanguageHandler languageHandler;
    private static PEHandlerService instancia;

    private PEHandlerService() {
        this.languageHandler = new LanguageHandler();
    }

    public static PEHandlerService getInstancia() {
        if (instancia == null) {
            instancia = new PEHandlerService();
        }
        return instancia;
    }
}
Shouldn't the two codes return

? Why does this only occur in Code 2?

Author: Daniela Morais, 2015-03-27

2 answers

Its first form is "more correct", that is, without test in method getInstance. The book Effective Java has discussed this subject deeply for many years.

Let's look at some points below...

Singleton without competition

The simplest implementation of the singleton pattern is this way:

private static PEHandlerService instancia;
public static PEHandlerService getInstancia() {
    if (instancia == null) instancia = new PEHandlerService();
    return instancia;
}

As you already know, this version Could generate two instances in a somewhat unusual scenario, i.e., if two threads run getInstance at the same time on the first method call.

Singleton competitor

To solve this, the easiest solution is to synchronize the method:

private static PEHandlerService instancia;
synchronized public static PEHandlerService getInstancia() {
    if (instancia == null) instancia = new PEHandlerService();
    return instancia;
}

This avoids concurrency problems, but generates a small delay in each call to the method to manage concurrency, in addition to the fact that if there are multiple threads only one can call the method at a time, possibly generating bottlenecks in a system highly competitive.

Concurrent Singleton with minimum synchronization

To slightly improve the above version, some authors propose the following construction:

private volatile static PEHandlerService instancia;
public static PEHandlerService getInstancia() {
    if (instancia == null) {
        synchronized (PEHandlerService.class) {
            if (instancia == null) instancia = new PEHandlerService();
        }
    }
    return instancia;
}

This causes synchronization to occur only on startup and not on other calls.

However, note the modifier volatile in the class attribute. It is necessary even with synchronization, because due to the Java memory model, especially before Java 5, they could still errors occur caused by one type of cache where other thread could still see the value null in the variable even after assignment by another thread in atomic mode.

Beware of multi-command initializations

A very important caution is not to assign the object to the static variable before it is fully initialized. Consider the following code:

private volatile static PEHandlerService instancia;
public static PEHandlerService getInstancia() {
    if (instancia == null) {
        synchronized (PEHandlerService.class) {
            if (instancia == null) {
                instancia = new PEHandlerService();
                instancia.setAlgumaDependencia(new Dependencia());
            }
        }
    }
    return instancia;
}

The above code assigns a new instance of PEHandlerService to the instancia and then pass some object to it. The problem is that like instancia != null, another thread can call the getInstancia method and retrieve the object before it receives the dependency. In this case you could have a NullPointerException.

Singleton preloaded without sync

To avoid all of these problems above, the simplest solution pointed out is to simply initialize your object singleton outside of the method getInstance , just like in your first example:

private static PEHandlerService instancia = new PEHandlerService();
public static PEHandlerService getInstancia() {
    return instancia;
}

If some type of boot is required, you can use a static boot Block:

private static PEHandlerService instancia;
static {
    instancia = new PEHandlerService();
    instancia.setDependencia(new Dependencia());
}
public static PEHandlerService getInstancia() {
    return instancia;
}

The biggest difference of this approach is that the object will no longer be initialized on demand (lazy initialization), but as soon as the class is used for the first time (eager initialization). This can be good or bad, depending on the case.

Concurrent Singleton without synchronization

To try to put everything together, that is, avoid synchronization and load the singleton in mode lazy , there are some alternatives.

One of these is to use a third class to load the static variable only when it is accessed. Example:

private static class SingletonLoader {
     private static PEHandlerService instancia = new PEHandlerService();
}
public static PEHandlerService getInstancia() {
    return SingletonLoader.instancia;
}

Alternative: use an enum

Another alternative to Single is to simply declare your class as a one-value Enum. Example:

public enum PEHandlerServiceSingleton {
    INSTANCE;

    //métodos aqui

}

And then you can access this as follows shape:

PEHandlerServiceSingleton.INSTANCE

Considerations

There are many different ways to use a pattern like Singleton. Each can be good or bad for certain situations and some hide certain problems.

However, once you understand the difference between implementations a little, it's not difficult to choose one that fits your solution best.

 6
Author: utluiz, 2015-03-27 16:52:11

Try to see if the error is not being caused elsewhere. Because your second code seems to be correct.

This is the correct way to implement a singleton:

//Crie uma variável private para armazenar a instancia
private static PEHandlerService instance;
public static PEHandlerService GetInstance(){
    //Verifica de instance é null. Caso seja, instancia PEHandlerService.
    if (instance == null)
         instance = new PEHandlerService();
    return instance; // retorna a instancia
}

//o resto do código

Any doubt is just talking.

 0
Author: João Luiz Grigoletti, 2015-03-27 12:35:43