Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Singleton & Multithreading in Java

Tags:

What is the preferred way to work with Singleton class in multithreaded environment?

Suppose if I have 3 threads, and all of them try to access getInstance() method of singleton class at the same time -

  1. What would happen if no synchronization is maintained?
  2. Is it good practice to use synchronized getInstance() method or use synchronized block inside getInstance().

Please advise if there is any other way out.

like image 708
vivekj011 Avatar asked Jun 17 '12 14:06

vivekj011


People also ask

What is an example of a singleton?

Example. The Singleton pattern ensures that a class has only one instance and provides a global point of access to that instance. It is named after the singleton set, which is defined to be a set containing one element. The office of the President of the United States is a Singleton.

Is singleton a good whisky?

The ScotchThis is a fairly viscous whisky which clings visibly to the glass as it moves and is something notable in the mouth feel as there is a distinct velvetiness to the finish. There is an earthy, nuttiness to the nose which is noticeably instantly and this is coupled beautifully with hints of pear.

What is singleton used for?

Singleton pattern is used for logging, drivers objects, caching and thread pool. Singleton design pattern is also used in other design patterns like Abstract Factory, Builder, Prototype, Facade etc. Singleton design pattern is used in core java classes also, for example java.

What is singleton pattern in Java?

In Java, Singleton is a design pattern that ensures that a class can only have one object. To create a singleton class, a class must implement the following properties: Create a private constructor of the class to restrict object creation outside of the class.


1 Answers

If you're talking about threadsafe, lazy initialization of the singleton, here is a cool code pattern to use that accomplishes 100% threadsafe lazy initialization without any synchronization code:

public class MySingleton {       private static class MyWrapper {          static MySingleton INSTANCE = new MySingleton();      }       private MySingleton () {}       public static MySingleton getInstance() {          return MyWrapper.INSTANCE;      } } 

This will instantiate the singleton only when getInstance() is called, and it's 100% threadsafe! It's a classic.

It works because the class loader has its own synchronization for handling static initialization of classes: You are guaranteed that all static initialization has completed before the class is used, and in this code the class is only used within the getInstance() method, so that's when the class loaded loads the inner class.

As an aside, I look forward to the day when a @Singleton annotation exists that handles such issues.

Edited:

A particular disbeliever has claimed that the wrapper class "does nothing". Here is proof that it does matter, albeit under special circumstances.

The basic difference is that with the wrapper class version, the singleton instance is created when the wrapper class is loaded, which when the first call the getInstance() is made, but with the non-wrapped version - ie a simple static initialization - the instance is created when the main class is loaded.

If you have only simple invocation of the getInstance() method, then there is almost no difference - the difference would be that all other sttic initialization would have completed before the instance is created when using the wrapped version, but this is easily dealt with by simply having the static instance variable listed last in the source.

However, if you are loading the class by name, the story is quite different. Invoking Class.forName(className) on a class cuasing static initialization to occur, so if the singleton class to be used is a property of your server, with the simple version the static instance will be created when Class.forName() is called, not when getInstance() is called. I admit this is a little contrived, as you need to use reflection to get the instance, but nevertheless here's some complete working code that demonstrates my contention (each of the following classes is a top-level class):

public abstract class BaseSingleton {     private long createdAt = System.currentTimeMillis();      public String toString() {         return getClass().getSimpleName() + " was created " + (System.currentTimeMillis() - createdAt) + " ms ago";     } }  public class EagerSingleton extends BaseSingleton {      private static final EagerSingleton INSTANCE = new EagerSingleton();      public static EagerSingleton getInstance() {         return INSTANCE;     } }  public class LazySingleton extends BaseSingleton {     private static class Loader {         static final LazySingleton INSTANCE = new LazySingleton();     }      public static LazySingleton getInstance() {         return Loader.INSTANCE;     } } 

And the main:

public static void main(String[] args) throws Exception {     // Load the class - assume the name comes from a system property etc     Class<? extends BaseSingleton> lazyClazz = (Class<? extends BaseSingleton>) Class.forName("com.mypackage.LazySingleton");     Class<? extends BaseSingleton> eagerClazz = (Class<? extends BaseSingleton>) Class.forName("com.mypackage.EagerSingleton");      Thread.sleep(1000); // Introduce some delay between loading class and calling getInstance()      // Invoke the getInstace method on the class     BaseSingleton lazySingleton = (BaseSingleton) lazyClazz.getMethod("getInstance").invoke(lazyClazz);     BaseSingleton eagerSingleton = (BaseSingleton) eagerClazz.getMethod("getInstance").invoke(eagerClazz);      System.out.println(lazySingleton);     System.out.println(eagerSingleton); } 

Output:

LazySingleton was created 0 ms ago EagerSingleton was created 1001 ms ago 

As you can see, the non-wrapped, simple implementation is created when Class.forName() is called, which may be before the static initialization is ready to be executed.

like image 61
Bohemian Avatar answered Nov 02 '22 15:11

Bohemian