import java.util.function.Supplier;

class Ideone {
  public static void main (String[] args) {
    Singleton.setSingletonFactory(SubSingleton.SUB_SINGLETON_FACTORY);
    Singleton instanceOne = Singleton.getInstance();
    Singleton instanceTwo = Singleton.getInstance();

    System.out.println(instanceOne == instanceTwo);

	try {
	  SubSingleton.SUB_SINGLETON_FACTORY.get();
	} catch (IllegalStateException e) {
	  System.out.println("Rightfully thrown " + e);
	}
  }
}

class Singleton {
  private static volatile Singleton INSTANCE = null;

  private static Supplier<? extends Singleton> factory;

  public static void setSingletonFactory(Supplier<? extends Singleton> factory) {
    Singleton.factory = factory;
  }

  public static Singleton getInstance() {
    if (INSTANCE == null) {
      synchronized (Singleton.class) {
        if (INSTANCE == null) {
          INSTANCE = factory.get();
        }
      }
    }
    return INSTANCE;
  }

  protected Singleton() {
    if (INSTANCE == null) {
      synchronized (Singleton.class) {
        if (INSTANCE == null) {
          // Set attribute of Singleton as necessary
        } else {
          throw cannotReinitializeSingletonIllegalStateException();
        }
      }
    } else {
      throw cannotReinitializeSingletonIllegalStateException();
    }
  }

  private static IllegalStateException cannotReinitializeSingletonIllegalStateException() {
    return new IllegalStateException("Cannot reinitialize Singleton");
  }
}

class SubSingleton extends Singleton {
  public static final Supplier<SubSingleton> SUB_SINGLETON_FACTORY = SubSingleton::new;

  private SubSingleton() {}
}