2

I ran across the AtomicReference class and was wondering if this could be a good way of creating a Singleton that is mutable and could be replaced for testing.

I know the double-lock checking has issues so I didn't want to go that route. Corrected as of JDK 1.5, https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html.
Also I would prefer to lazily instantiate the singleton instead of initializing it. For example, during testing I wouldn't want to use the default class SimpleExample but in certain cases it is either expensive to create or problematic in certain environments. I would prefer to be able to replace it prior to the request.

public class SingletonExample {

  private static AtomicReference<SingletonExample> sInstance = new AtomicReference<>();

  private SingletonExample() {
  }

  public static SingletonExample getInstance() {
      return sInstance.updateAndGet(u -> u != null ? u : new SingletonExample());
  }

  @VisibleForTesting
  static void setInstance(SingletonExample singletonExample) {
      sInstance.set(singletonExample);
  }
}

Here are my questions:

  1. Is there a big performance hit?
  2. Is there an issue that I am not aware of using it as a Singleton?
  3. What are reasonable alternatives?
Alex Beggs
  • 1,187
  • 2
  • 11
  • 17
  • *What are reasonable alternatives?* - Do not use a signleton. – lexicore Mar 20 '18 at 20:06
  • Your presented code doesn't seem to offer much you couldn't do with a regular `volatile` field. So you want to use a different implementation for prod and for testing, that's understandable I suppose, but what do you mean with "either expensive to create or problematic in certain environments"? I'd bet dollars to donuts that there are lots of better ways to do what you need than to use something as crude as the singleton pattern. – Kayaman Mar 20 '18 at 20:38
  • Also, *mutable* singleton is a road to hell. Just wait for someone to find out that they could set a different implementation they'd prefer for their needs. – lexicore Mar 20 '18 at 21:11
  • “*Also I would prefer to lazily instantiate the singleton instead of initializing it*” but class initialization is as lazy as your code. It will happen just when `getInstance()` is invoked for the first time. You are just wasting resource when `getInstance()` is invoked more than one time. – Holger Mar 25 '19 at 08:47

1 Answers1

1
  1. Is there a big performance hit?

As with anything: it depends.

"With low to moderate contention, atomics offer better scalability; with high contention, locks offer better contention avoidance."

From "Java Concurrency In Practice" by Goetz section 15.3.2

  1. Is there an issue that I am not aware of using it as a Singleton?

Because you're not using locking, the parameter lamda looks like it could be run by multiple threads at the same time. So you could have multipe SingletonExample objects created and set, but each thread would see each update:

public static SingletonExample getInstance() {
  return sInstance.updateAndGet(u -> u != null ? u : new SingletonExample());
}
  1. What are reasonable alternatives?

I would stick with simple locking, since:

  1. It works as you intended. So you only create SingletonExample once.
  2. Allows you to group state variables together, which you can't do with volatile or AtomicReferences.
DataDino
  • 1,507
  • 1
  • 15
  • 30