2

I was just reading concurrency in practice. I came to know it is necessary to use volatile keyword in double checked locking mechanism for field otherwise thread can read stale value of not null object. Because it is a possibility of reordering instruction without use of volatile keyword. Because of that object reference could be assigned to resource variable before calling constructor. so thread could see partially constructed object.

I have a question regarding that.

I assume synchronized block also restricts compiler from instruction reordering so why we need volatile keyword here?

public class DoubleCheckedLocking {
    private static volatile Resource resource;
    public static Resource getInstance() {
        if (resource == null) {
            synchronized (DoubleCheckedLocking.class) {
                if (resource == null)
                    resource = new Resource();
            }
        }
        return resource;
    }
}
Turing85
  • 18,217
  • 7
  • 33
  • 58
sdindiver
  • 491
  • 1
  • 5
  • 19
  • 2
    [Double-checked locking: Clever, but broken: Do you know what synchronized *really* means?](https://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking--clever--but-broken.html) – Elliott Frisch Apr 15 '18 at 10:26
  • 1
    @ElliottFrisch - clever, broken when Java was young (your link is from 2001), [working since 2004](http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#dcl), but worse than cleaner alternatives (see links in my answer) – tucuxi Apr 15 '18 at 11:29

3 Answers3

8

The JMM only guarantees that a thread T1 will see a properly initialized object created by another thread T2 inside a synchronized block if the calling thread (T1) also reads it from a synchronized block (on the same lock).

Since T1 could see the resource as not null, and thus return it immediately without going though the synchronized block, it could get an object but not see its state properly initialized.

Using volatile brings back that guarantee, because there is a happens-before relationship between the write of a volatile field and the read of that volatile field.

Hearen
  • 7,420
  • 4
  • 53
  • 63
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • I have a doubt here. What volatile is doing here is stopping compiler to reorder instruction of assigning reference of object and constructor execution? I mean constructor would gets called before assigning object reference to **resource** reference variable. Is it true? – sdindiver Apr 15 '18 at 11:33
  • Basically es, except for a major point: the compiler has nothing to do with this. That happens at runtime. Also, you shouldn't think in terms of what volatile forces the runtime to do. You should think in terms of the guarantees it offers, whatever the way this guarantee is fulfilled at runtime. – JB Nizet Apr 15 '18 at 11:37
3

Volatile is necessary in this case, as others have observed, because a data race is possible when first accessing the resource. There is no guarantee, absent volatile, that thread A, reading a non-null value, will actually access the fully initialized resource -- if it is, at the same time, being built in thread B within the synchronized section, which thread A has not yet reached. Thread A could then try to work with a half-initialized copy.

Double-checked locking with volatile, while working since JSR-133 (2004), is still not recommended, as it is not very readable and not as efficient as the recommended alternative:

private static class LazyResourceHolder {
  public static Resource resource = new Resource();
}

...

public static Resource getInstance() {
  return LazyResourceHolder.something;
}

This is the Initialize-On-Demand Holder Class idiom, and according to the above page,

[...] derives its thread safety from the fact that operations that are part of class initialization, such as static initializers, are guaranteed to be visible to all threads that use that class, and its lazy initialization from the fact that the inner class is not loaded until some thread references one of its fields or methods.

tucuxi
  • 17,561
  • 2
  • 43
  • 74
  • So How volatile is ensuring other thread, it would see fully initialized object? volatile means write happens before read. Could it not be possible first thread has assigned the allocated memory to reference variable. Allocating memory to reference variable is **writing** case. then other thread is reading the value of reference variable that is (reading case). But still your constructor does not get called. – sdindiver Apr 15 '18 at 11:46
  • @sdindiver that's what could happen if you were not using volatile, and it's precisely what volatile (and all other means to have a happens-before relationship) guarantees will not happen. When you have a happens-before guarantee, it means that the runtime can't apply reorderings that would go against the semantics of the language (where the normal order is: first invoke the constructor, then assign the result to the variable). – JB Nizet Apr 15 '18 at 11:51
  • The full explanation of this Pugh's idiom see here: https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom – Daniel Zin Aug 31 '22 at 10:47
-3

Actually there is no need to use volatile here. Using volatile will mean that multiple threads will each time the instance variable is used in a thread method it will not optimize the memory read away but make sure it is read again and again. The only times I've deliberately used volatile is in threads where I have a stop indicator (private volatile boolean stop = false;)

Creating singletons like in your sample code is needlessly complex and doesn't offer any actual speed improvements. The JIT compiler is very good at doing thread locking optimizations.

You'll be better out creating singletons using:

public static synchronized Resource getInstance() {
    if (resource == null) {
        resource = new Resource();
    }
    return resource;
}

Which is much easier to read and infer its logic for human beings.

See also Do you ever use the volatile keyword in Java?, where volatile is indeed generally used for some end-of-loop flag in threads.

M. le Rutte
  • 3,525
  • 3
  • 18
  • 31
  • There **is** a need to volatile. – JB Nizet Apr 15 '18 at 10:27
  • With the double check, yes, but I stand by not needing to do such a double check. – M. le Rutte Apr 15 '18 at 10:29
  • Yes, but that's irrelevant. The question asks why volatile is needed when DCL is used, not if DCL should be used. – JB Nizet Apr 15 '18 at 10:30
  • As elliot frisch added as comment DCL is broken, I think it is better to point the OP in the right direction. – M. le Rutte Apr 15 '18 at 10:34
  • DCL is broken **if you don't make the field volatile**. And your answer says: *there is no need to use volatile here*. So **you**'re pointing the OP, and all the future readers in the wrong direction. – JB Nizet Apr 15 '18 at 10:35
  • The reason to make the field `volatile` is to ensure memory fences (hardware/JIT level) and prevent re-ordering (JIT/compiler level): the exact "flexibility" of not-safe-code-working depends on a number of factors, but the only "guaranteed" method is to ensure the appropriate memory fences/ordering (as does volatile under Java 5+). It is also possible to use explicit memory barriers.. Anyway. making the entire method synchronized is not DCL - and is thus *not applicable to the question* - and does not have the same 'issues', as *all* the access is within the critical region. – user2864740 Oct 17 '18 at 23:12