Reci
Reci

Reputation: 4274

Best practise to create singleton in concurrent environment?

I'm seeking an answer to a question similar to Is it appropriate to use AtomicReference.compareAndSet to set a reference to the results of a database call? but with different requirement.

The goal is to create an instance of ObjectWithSideEffectConstructor only once to avoid duplicate side effects. The construction must happen in setUp(). Multiple threads will call setUp(). Similarly there will be a tearDown() for reclaiming the resource from the object, which is omitted here. Question: what is the best practice to achieve the goal?

Simply using AtomicReference will not be enough, because the constructor will be executed first, so as the side effect.

private static AtomicReference<ObjectWithSideEffectConstructor> ref =
  new AtomicReference<ObjectWithSideEffectConstructor>()

void setUp() {
  ref.compareAndSet(null, new ObjectWithSideEffectConstructor());
}

Using the answer from Is it appropriate to use AtomicReference.compareAndSet to set a reference to the results of a database call? will not work, because volatile lacks of synchronization. There will be window that multiple threads enters if.

private static volatile ObjectWithSideEffectConstructor obj;

void setUp() {
  if (obj == null) obj = new ObjectWithSideEffectConstructor();
}

Simple fix would be

private static ObjectWithSideEffectConstructor obj;
private static final Object monitor = new Object();

void setUp() {
  synchronized (monitor) {
    if (obj == null) obj = new ObjectWithSideEffectConstructor();
  }
}

Similarly, DCL with volatile monitor may give better read performance. But both requires some level of synchronization, thus expect worse performance.

Also we can use FutureTask. It is more efficient because once the object is created, subsequent FutureTask.get() will return without blocking. But it is definitely much more complicated than synchronized.

private static final AtomicReference<FutureTask<ObjectWithSideEffectConstructor>> ref =
  new AtomicReference<FutureTask<ObjectWithSideEffectConstructor>>();

void setUp() {
  final FutureTask<ObjectWithSideEffectConstructor> future =
    new FutureTask<ObjectWithSideEffectConstructor>(
      new Callable<ObjectWithSideEffectConstructor>() {
        @Override
        public ObjectWithSideEffectConstructor call() throws InterruptedException {
          return new ObjectWithSideEffectConstructor();
        }
      }
    );
  if (ref.compareAndSet(null, future)) future.run();
  ref.get().get();
}

Thanks for suggestions.

Upvotes: 3

Views: 2877

Answers (6)

ruakh
ruakh

Reputation: 183270

For what it's worth, the FutureTask approach doesn't actually require all of that code; the AtomicReference is not needed, and there shouldn't be any need to call both run() and get(). So you can simplify it slightly:

private static final Future<ObjectWithSideEffectConstructor> future =
  new FutureTask<>(
    new Callable<ObjectWithSideEffectConstructor>() {
      @Override
      public ObjectWithSideEffectConstructor call() throws InterruptedException {
        return new ObjectWithSideEffectConstructor();
      }
    }
  );

void setUp() {
  future.run(); // or future.get(), if you want to get any exception immediately
}

Furthermore, with Java 8, the initialization expression can be written much more briefly; the above can be reduced to just:

private static final Future<ObjectWithSideEffectConstructor> future =
  new FutureTask<>(ObjectWithSideEffectConstructor::new);

void setUp() {
  future.run(); // or future.get(), if you want to get any exception immediately
}

Upvotes: 0

Bohemian
Bohemian

Reputation: 424993

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 coding pattern is known as the Initialization-on-demand holder idiom. It 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.

Upvotes: 3

phil_20686
phil_20686

Reputation: 4080

Always use the enum type for singletons, not only does it enforce the singleton elegantly, it also prevents common programming errors like when a singleton inherits a clone() method from its superclass and the programmer forgets to override it with a private method declaration. Or when you forget to override deserialisable, and allow programmers to serialise your singleton, declare a new instance, and then deserialise the old one.

Alternatively, if you use a static factory pattern, you can declare instance fields transient and use a readresolve method. This provides the flexibility if you might change your mind about whether it should be a singleton later in the design process.

Credit: Answer based on Effective Java by J Bloch (Item 3), a book every Java programmer should read, own and refer to regularly...

Upvotes: 1

Sandip Wankhede
Sandip Wankhede

Reputation: 66

Implementing Singleton in Java 5 or above version using Enum:

Enum is thread safe and implementation of Singleton through Enum ensures that your singleton will have only one instance even in a multithreaded environment. Let us see a simple implementation:

public enum SingletonEnum 
{
    INSTANCE;
    public void doStuff()
    {
        System.out.println("Singleton using Enum");
    }
}

// How to use in other classes
public static void main(String[] args) 
{
    SingletonEnum.INSTANCE.doStuff();
}

Upvotes: 1

TwoThe
TwoThe

Reputation: 14259

The synchronized method would be the way to go. If you actually need the performance you need to restructure your code to have a single-threaded pre-initialization. Using any other form will cause side-effects as described in the singleton pattern.

Upvotes: 0

Thomas W
Thomas W

Reputation: 14164

I assume you only want one ObjectWithSideEffectConstructor. There's a question here as to whether 1) it's the side effect happening twice your want to avoid, or 2) you just need to end up with a consistent (singleton) reference.

Either way, synchronized is a good standard option. It will keep other threads from constructing a second instance, while the first thread is in setup.

If you're in situation 1), using synchronized is probably required. If performance after startup were critical, you could possibly consider preceding the synchronized section with an AtomicReference.get() fast-path, to enable the synchronized section to be avoided after startup is complete.

If you're in situation 2), then -- it's not really clear from your question -- there is a side-effect of construction, but you don't care about duplicating that -- just so long as the client code only "sees" a consistent single reference.

In that second case, you could use AtomicReference.get() to check whether it's already initialized, and return if so. Threads would then enter the "race section" where they would construct (potentially multiple) ObjectWithSideEffectConstructor. Lastly, there would be a compareAndSet so that only one thread set the singleton.. with failing threads falling back to anAtomicReference.get() to take the correct singleton.

Performancewise, a single call to AtomicReference is faster than a synchronized block -- but I'm not sure if, with the double- and triple-checking & construction of unwanted side-effect objects, the second approach would be. A simple synchronized block might, again, be simpler & faster.

I'd be interested to see some measurements.

Upvotes: 0

Related Questions