I am the founder and CEO of Data Geekery GmbH, located in Zurich, Switzerland. With our company, we have been selling database products and services around Java and SQL since 2013. Ever since my Master's studies at EPFL in 2006, I have been fascinated by the interaction of Java and SQL. Most of this experience I have obtained in the Swiss E-Banking field through various variants (JDBC, Hibernate, mostly with Oracle). I am happy to share this knowledge at various conferences, JUGs, in-house presentations and on our blog. Lukas is a DZone MVB and is not an employee of DZone and has posted 248 posts at DZone. You can read more from them at their website. View Full User Profile

Java Trivia: the Double-Checked Locking Pattern

02.12.2013
| 3477 views |
  • submit to reddit

In most cases, it is sufficient to simply mark a lazy initialising method as synchronized. The following example can be found in the Wikipedia article about double-checked locking:

// Correct but possibly expensive multithreaded version
class Foo {
    private Helper helper = null;
    public synchronized Helper getHelper() {
        if (helper == null) {
            helper = new Helper();
        }
        return helper;
    }
 
    // other functions and members...
}

Sometimes, however, you want to avoid obtaining a lock on the Foo instance every time you access Foo’s Helper. Then you may choose to apply double-checked locking (only with Java 1.5+. A good article why it didn’t work prior to Java 1.5 can be found here). If you forget how it works, or doubt whether it works at all, consider looking at the source code of java.io.File.toPath():

// "volatile" is of the essence, here:
private volatile transient Path filePath;

public Path toPath() {
    Path result = filePath;
    if (result == null) {
        synchronized (this) {
            result = filePath;
            if (result == null) {
                result = FileSystems.getDefault().getPath(path);
                filePath = result;
            }
        }
    }
    return result;
}



 

Published at DZone with permission of Lukas Eder, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Nim Lhûg replied on Tue, 2013/02/12 - 2:12am

You really want to avoid using volatile variables, from a performance point of view. It makes it harder for the JVM to perform optimizations. Instead, just rely on this synchronized approach. The JVM can optimize the lock away in some cases, and in others it won't matter a hoot.

Besides, from a readability and complexity point of the view, the second approach is just a nightmare.

If synchronized lazy initialization is a bottle neck in your application, then there's likely something seriously wrong with the design and you might want to avoid lazy initialization entirely.

Lukas Eder replied on Tue, 2013/02/12 - 3:20am in response to: Nim Lhûg

Yes, I've noticed that adding volatile to code that is benchmarked leads to serious slowing down. Still, as the example shows, lazy initialisation may be slow. In the example, it involves disk I/O. Do you think that synchronizing toPath() would've been better?

Nim Lhûg replied on Tue, 2013/02/12 - 4:48am in response to: Lukas Eder

As much as I hate to say it, but "it depends". It depends on how toPath() is used, where it's called from, if it's called by many threads or mostly by one thread. If it's called mostly from one thread, then synchronize it. The JVM can then bias the lock to the last thread that called it, and as long as that thread keeps on calling it there won't be any overhead.

Adolfo Benedetti replied on Tue, 2013/02/12 - 7:03am

AFAIK the Initialization on demand holder idiom pattern is a cleaner and more efficient way to do the job, or you can consider an Java Enum Singleton as well.

public class Something {
        private Something() {
        }
        private static class LazyHolder {
                private static final Something INSTANCE = new Something();
        }
        public static Something getInstance() {
                return LazyHolder.INSTANCE;
        }
}

Lukas Eder replied on Tue, 2013/02/12 - 9:03am in response to: Adolfo Benedetti

Adolfo: Both of your approaches are useful for lazy static initialisation, e.g. when singleton instances need to be initialised. The article's example is about lazy initialising thousands of objects, hence these techniques that use classloader threadsafety features aren't useful.

Dan Howard replied on Wed, 2013/02/13 - 8:41am

Just use a fricking enum already.


public enum MyEnum {
    INSTANCE;
  private int something;

  public int getSomething() {
    return something;
  }
}

Lukas Eder replied on Wed, 2013/02/13 - 9:42am in response to: Dan Howard

As I mentioned before, this is not about singletons or about static lazy initialisation... You can hardly put an enum for that purpose in java.io.File...?

Gernot Veith replied on Wed, 2013/02/13 - 2:15pm

 The double checked pattern is mainly an anti pattern. It does not really work in Java. It is discussed here

gve

Lukas Eder replied on Wed, 2013/02/13 - 2:54pm in response to: Gernot Veith

Why is it an anti-pattern? It works well with Java 5+ as stated both in the original article, as well as in the link you posted (which is also contained in the original article, by the way).

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.