4

I was wondering about singleton in enum and it's performance.

When we have multithreaded environment we have to synchronize moment, when an instance is created.

Simply, we can use synchronized mod, for function called getInstance() which create instance Somethink like that:

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

It's lazy implementation it's good for me. But synchronized method is slow. We can use double-locking to make it faster.

How about enum? When we implement singleton as enum, instance of singleton will be created as first use. Next use, return current instance.

How it works? When we want to get existing instance, there is implicit synchronized method which are slow? Or there is Double-lock implemented?

Thomas Banderas
  • 1,681
  • 1
  • 21
  • 43

3 Answers3

3

Enum is thread-safe and is also the recommended way to implement a Singleton.

That said, enum is not lazily loaded. If you want a lazy-loaded singleton, you can use the Holder pattern (which is thread-safe as well):

class LazySingleton {

    private LazySingleton() {}

    private static class SingletonHelper{
        private static final LazySingleton INSTANCE = new LazySingleton();
    }

    public static LazySingleton getInstance(){
        return SingletonHelper.INSTANCE;
    }
}
Nir Alfasi
  • 53,191
  • 11
  • 86
  • 129
  • This `SingletonHelper` is only needed, if the containing class bears more features than the singleton and its operations. Otherwise, the lazy class loading of `LazySingleton` works exactly like the lazy class loading of `SingletonHelper`, whether `LazySingleton` is an `enum` or not. – Holger Nov 27 '17 at 12:14
1

There is no lazy initialization with an enum. It will simply create the instance when the class is loaded.

When we implement singleton as enum, instance of singleton will be created as first use.

That is only true if by "first use" you actually mean "when the class is loaded".

In other words, using your example, an enum would be equivalent to:

private static final Singleton instance = new Singleton();

public static Singleton getInstance() {
    return instance;
}
Costi Ciudatu
  • 37,042
  • 7
  • 56
  • 92
  • The `enum` constant is created when the class is *initialized*. Exactly like your `instance` field. The time of the initialization [is exactly specified](https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.4.1). It can be summarized to “on the first use”… – Holger Nov 27 '17 at 12:15
1

The initialization of enum constants happens in the class initializer, similar to had you written

static final Singleton instance = new Singleton();

or

static final Singleton instance;
static {
    instance = new Singleton();
}

The safety comes from the fact that the JVM perform class initialization under a JVM specific lock:

Because the Java programming language is multithreaded, initialization of a class or interface requires careful synchronization, since some other thread may be trying to initialize the same class or interface at the same time. … The implementation of the Java Virtual Machine is responsible for taking care of synchronization and recursive initialization by using the following procedure.

For each class or interface C, there is a unique initialization lock LC. The mapping from C to LC is left to the discretion of the Java Virtual Machine implementation.

I left out a lot of technical details from the specification, as to a Java programmer, the most important point is that there is a safety mechanism implemented by every conforming JVM. The end of the section has the comment:

An implementation may optimize this procedure by eliding the lock acquisition in step 1 (and release in step 4/5) when it can determine that the initialization of the class has already completed, provided that, in terms of the memory model, all happens-before orderings that would exist if the lock were acquired, still exist when the optimization is performed.

This is, of course, an important point of this implementation of the singleton pattern, that later access to the static final field does not need to acquire a lock. Since all classes go from the uninitialized to the initialized state exactly once and it affects every operation (including all other possibilities to implement the singleton pattern), you can expect every JVM to do this fundamental optimization. Even if a particular JVM does not do this, the static final field would be the fastest lazy singleton implementation on that virtual machine…

Community
  • 1
  • 1
Holger
  • 285,553
  • 42
  • 434
  • 765