4

I have created three objects from class A. All of these three objects can update a value which is stored in private static volatile variable in class A. Updating this variable is done within a synchronized block with a certain criteria. I want to synchronize the block by using a lock-object.

So first the object are created in MainClass

A a1 = new A();
A a2 = new A();
A a3 = new A();

And after this the objects start to live their own lives. Here's a simplified example of my class A.

public class A{
    private static volatile String sharedVariable;
    Object lockObject = new Object();

    private void updateVariable(String newValue){
        //... some code
        synchronized(lockObject){
            //... code to check whether to update the value
            sharedVariable = newValue;
        }
    }

Should I declare lockObject as private static volatile, if I want the synchronized block to be synchronized with all instances and all threads of class A? If I use the class (this) to synchronize the block, will it accomplish the same thing?

I think that with the above code the all of the instances of class A create their own lockObject and synchronized with it. Therefore the synchronization would only happen with threads within each instance (a1, a2 and a3). Is this correct?

Matti
  • 147
  • 5

2 Answers2

5

What volatile gives is a happens-before guarantee that subsequent read in all threads will see the most recently written values.

The purpose of volatile and static doesn't mix here.

If you define the lock object to be an instance variable, then it'll be created for each instance of A, which is definitely not desired.

Since the object on which synchronized access is required is static, you need to create a static final lock object. final (although not necessary but a good practice) ensures that the lock object is visible and isn't changed at runtime and static make a single lock to access the object

public class A{
    private static volatile String sharedVariable;
    private static final Object lockObject = new Object();

    private void updateVariable(String newValue){
        //... some code
        synchronized(lockObject){
            //... code to check whether to update the value
            sharedVariable = newValue;
        }
    }

More on this:

Community
  • 1
  • 1
Gurwinder Singh
  • 38,557
  • 6
  • 51
  • 76
  • Shouldn't lockObject be volatile to prevent instances of the class from creating a cached version of it? – Matti Jan 01 '17 at 11:46
  • I mean even though you defined lockObject as final it still holds data regarding the lock which changes when a thread is executing the synchronized block (or when it stops executing it). Doesn't this allow each instance of the class to have a cached copy of the lockObject? – Matti Jan 01 '17 at 12:17
  • No. final does **not** allow the reference to change. *it still holds data regarding the lock* - lock is on the object, *not* what's in the object. I've updated my answer to clarify more. – Gurwinder Singh Jan 01 '17 at 12:21
  • Thank you. I think I got it now. – Matti Jan 01 '17 at 12:39
  • 2
    Final is good practice but not necessary here. Generally a good answer but I'd remove the informal (And therefore wrong) definition of volatile. Volatile doesn't just create memory barriers (that's not enough to implement the JMM correctly) and it has nothing to do with flushing caches to main memory: As a matter of fact on x86 a volatile variable can stay in cache without any problem. – Voo Jan 01 '17 at 19:47
  • @Voo Thanks for the comment. Updated. – Gurwinder Singh Jan 01 '17 at 19:50
0

Object level lock is not suffice to guard class variables. You need class level lock.

volatile variable are meant for different purpose. It is useful when you update the value of variable in one thread and read the value of variable from many threads.

Have a look at below solutions.

  1. Use static final lock as proposed by Gurwinder Singh
  2. Use synchronized(A.class) to update static variable
  3. Use AtomicReference

Related SE questions:

When to use AtomicReference in Java?

Difference between volatile and synchronized in Java

Community
  • 1
  • 1
Ravindra babu
  • 37,698
  • 11
  • 250
  • 211