Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I synchronize a static volatile variable?

There are a few questions on this subject, but most skirt around this issue because it's not the intent of the question.

If I have a static volatile in my class:

private static volatile MyObj obj = null;

and in a method below I do:

public MyObj getMyObj() {
    if (obj == null) {
        obj = new MyObj();// costly initialisation
    }
    return obj;
}

will I need to synchronize to ensure only one thread writes to the field, or will any writes be immediately visible to other threads evaluating the obj == null conditional?

To put it another way: does volatile get you around having to synchronize access to writes on a static variable?

like image 267
Alex Avatar asked May 22 '12 07:05

Alex


People also ask

Do I need to synchronize volatile?

Effectively, a variable declared volatile must have it's data synchronized across all threads, so that whenever you access or update the variable in any thread, all other threads immediately see the same value.

Do we need to synchronize static methods?

You do need to make m2 synchronized. Otherwise someone can call that method at the same time. I am assuming m2 would be considered for being synchronized, otherwise it is a moot point.

Can static and volatile be used together?

Even if the static variables are shared variables, but in different thread there can be different values for a static variable in the local cache of a thread. To make it consistent for all threads, just declare it as static volatile . So each time it will fetch from main memory.

Does synchronization technics are required for volatile variable?

Noncompliant Code Example However, volatile flag still fails to provide the atomicity and visibility guarantees needed for synchronization primitives to work correctly. The volatile keyword does not promise to provide the guarantees needed for synchronization primitives.


Video Answer


2 Answers

You'd definitely need some sort of locking to ensure that only one thread writes to the field. Regardless of the volatility, two threads can both "see" that obj is null, and then both start initializing with your current code.

Personally I'd take one of three options:

  • Initialize on class load (knowing that that will be lazy, but not as lazy as waiting until getMyObj is first called):

    private static final MyObj obj = new MyObj();
    
  • Use unconditional locking:

    private static MyObj obj;
    private static final Object objLock = new Object();
    
    public static MyObj getMyObj() {
        synchronized(objLock) {
            if (obj == null) {
                obj = new MyObj();
            }
            return obj;
        }
    }
    
  • Use a nested class for laziness that way:

    public static MyObj getMyObj() {
        return MyObjHolder.obj;
    }
    
    private static class MyObjHolder {
        static final MyObj obj = new MyObj();
    }
    
like image 157
Jon Skeet Avatar answered Oct 20 '22 21:10

Jon Skeet


Yes, you should absolutely synchronize (or use a better idiom like the Singleton Holder idiom). Otherwise you run the risk of multiple threads initializing your object multiple times (and then subsequently using different instances).

Consider a sequence of events like this:

  1. Thread A enters getMyObj() and sees that obj == null
  2. Thread B enters getMyObj() and sees that obj == null
  3. Thread A constructs a new MyObj() - let's call it objA
  4. Thread B constructs a new MyObj() - let's call it objB
  5. Thread A assigns objA to obj
  6. Thread B assigns objB to obj (which is not null anymore at this point, so the reference to objA, assigned by Thread A, is overwritten)
  7. Thread A exits getMyObj() and starts to use objA
  8. Thread B exits getMyObj() and starts to use objB

This scenario can happen with any number of threads. Note that although here, for the sake of simplicity, I assumed a strict ordering of events, in a real multithreaded environment events 1-2, 3-4 and/or 7-8 can partly or fully overlap in time, without changing the end result.

An example to the holder idiom:

public class Something {
    private Something() {
    }

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

    public static Something getInstance() {
        return LazyHolder.INSTANCE;
    }
}

This is guaranteed to be safe, as INSTANCE is final. The Java memory model guarantees that final fields are initialized and made visible correctly to any number of threads, upon loading the containing class. Since LazyHolder is private and is referenced only by getInstance(), it will only get loaded when getInstance() is first called. And at that point, INSTANCE is initialized in the background and published safely by the JVM.

like image 35
Péter Török Avatar answered Oct 20 '22 23:10

Péter Török