hbase-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Paul Cowan <co...@aconex.com>
Subject Re: Review Request: HBASE-2578
Date Wed, 26 May 2010 04:16:28 GMT
On 26/05/2010 1:54 PM, Ryan Rawson wrote:
> Thanks for that salient comment. Perhaps someone can give us the right
> pattern for no lock Singleton initialization.

There are really only two things which complicate thread-safe singletons:

1) Having a setter, so you can replace the singleton
2) Lazy initialization. The only excuse for this is having a 
horribly-expensive-to-create singleton, which may not even be used, and 
you don't under any circumstances wish to create it unless it's needed. 
This is hard to get right, and 99% of the time you should just 
instantiate it at class initializion time and forget it.

In this case, 1) applies, but 2) doesn't; luckily 1) is a lot easier to 
get right than 2).

Simplest 'correct' patterns are:


Basic Singleton (neither #1 nor #2 apply)
-------------------------------------------

public class Thing {
    private static final Thing INSTANCE = new AwesomeThing();

    public Thing get() {
       return INSTANCE;
    }
}

this is easy, simple, performant (no synchronization or locking at all) 
and 100% thread-safe (as long as INSTANCE is final).



Replacable Singleton (#1 applies)
-------------------------------------------
public class Thing {
    private static volatile Thing instance = new AwesomeThing(); // 
Note: volatile

    public Thing get() {
       return instance;
    }

    public void set(Thing newThing) {
       this.instance = newThing;
    }
}

Nearly as easy, all that's required here is a volatile instance which 
gives you the correct happens-before relationship.



Lazy-Initialized Singleton (#2 applies)
-------------------------------------------
Avoid if possible, but if not, one of:

Synchronized Getter:
    public synchronized Thing get() {
       if (instance == null) {
           instance = new AwesomeThing();
       }
       return instance;
    }

Double-checked locking (ONLY works in Java 5+)
    public Thing get() {
       if (instance == null) {
           synchronized (ThingHolder.class) {
              if (instance == null) { // Yes, you need this
                  instance = new AwesomeThing();
              }
          }
       }
       return instance;

Use java classloading locking guarantees + holder class (see: Effective 
Java)
    class ThingHolder {
        private static final Thing INSTANCE = new AwesomeThing();
    }

    class Thing {
        public Thing getThing() {
            return ThingHolder.instance;
        }
    }



Lazy-Initialized Settable Singleton (#1 + #2 apply)
-------------------------------------------
You almost certainly don't need this. You think you do, but you don't. 
Find a better way. :)


Hope that helps.

Cheers,

Paul

Mime
View raw message