[Design Pattern] Erzeugende Muster: Singleton


#1
Hallo,

dieser Beitrag erklärt das erzeugende Muster: Singleton

- Beispiele Verschiedene Singleton Varianten
- Probleme aufzeigen (Visibility, Threading, Seralisierung, ClassLoader Problematik)

Java:
package de.tutorials.design.patterns.creational;

import java.net.URL;
import java.net.URLClassLoader;

public class SingletonPatternExample {
  public static void main(String[] args) {
    
    
    System.out.println(SingletonWithDCL.getInstance());
    System.out.println(SingletonWithDCL.getInstance());
    System.out.println(SingletonWithEagerInitialization.getInstance());
    System.out.println(SingletonWithEagerInitialization.getInstance());
    System.out.println(SingletonWithHolder.getInstance());
    System.out.println(SingletonWithHolder.getInstance());
    System.out.println(EnumBaseSingleton.INSTANCE + " " + System.identityHashCode(EnumBaseSingleton.INSTANCE));
    System.out.println(EnumBaseSingleton.INSTANCE + " " + System.identityHashCode(EnumBaseSingleton.INSTANCE));
    
    
    demoMultiClassloaderProblem();
    
  }
  

  public static class TestEnv{
    public static void run() {
      System.out.println("Current classloader: " + TestEnv.class.getClassLoader());
      System.out.println(SingletonWithHolder.getInstance());
      System.out.println(SingletonWithHolder.getInstance());
    }
  }
  
  private static void demoMultiClassloaderProblem() {
    System.out.println("#### demoMultiClassloaderProblem");
    try {
      newTestEnv().getMethod("run").invoke(null);
      newTestEnv().getMethod("run").invoke(null);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }


  protected static Class<?> newTestEnv() throws ClassNotFoundException {
    URLClassLoader classLoader = new URLClassLoader(new URL[]{TestEnv.class.getProtectionDomain().getCodeSource().getLocation()},null /* no parent classloader */);
    Class<?> clazz = classLoader.loadClass(TestEnv.class.getName());
    return clazz;
  }


  public static class SingletonWithDCL{
    private static volatile SingletonWithDCL instance; //volatile is very important here -> only volatile guarantees that other threads
                                                        //can "see" the changed value
    
    private SingletonWithDCL() {} //private constructor to prevent instantiation
    
    public static SingletonWithDCL getInstance(){
      if(instance == null){ //DCL = Double Checked Locking
        synchronized (SingletonWithDCL.class) {
          if(instance == null){
            instance = new SingletonWithDCL();
          }
        }
      }
      return instance;
    }
    
    private Object readResolve(){
      return getInstance(); //return the existing instance during serialization
    }
  }
  
  public static class SingletonWithEagerInitialization{
    private static final SingletonWithEagerInitialization instance = new SingletonWithEagerInitialization(); // classloader guarantees initialization
    
    private SingletonWithEagerInitialization(){}
    
    public static SingletonWithEagerInitialization getInstance() {
      return instance;
    }
    
    private Object readResolve(){
      return instance;
    }
  }
  
  public static class SingletonWithHolder{
    private static class Holder{
      private static final SingletonWithHolder instance = createInstance();

      public static SingletonWithHolder createInstance() {
        return new SingletonWithHolder();
      }  
    }
    
    public static SingletonWithHolder getInstance(){
      return Holder.instance; //classloader ensures class / singleton initialization
    }
    
    private Object readResolve(){
      return getInstance();
    }
  }
  
  
  public static enum EnumBaseSingleton{
    INSTANCE;
  }
}
Ausgabe:
Code:
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithDCL@4fe5e2c3
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithDCL@4fe5e2c3
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithEagerInitialization@164f1d0d
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithEagerInitialization@164f1d0d
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithHolder@45bab50a
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithHolder@45bab50a
INSTANCE 1807500377
INSTANCE 1807500377
#### demoMultiClassloaderProblem
Current classloader: java.net.URLClassLoader@544a5ab2
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithHolder@6af62373
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithHolder@6af62373
Current classloader: java.net.URLClassLoader@459189e1
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithHolder@527c6768
de.tutorials.design.patterns.creational.SingletonPatternExample$SingletonWithHolder@527c6768
Gruß Tom