Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java volatile variables and synchonized getters

I am doing some experiments with java concurrency with book Java "concurrency in practise".

I have next question: Is the syncronized getter method equals with volatile private variable? Some code:

public class ConsoleApp {

private static boolean ready;
private static int number;



public synchronized static boolean isReady() {
    return ready;
}



private static class ReaderThread extends Thread {
    public void run() {
        while (!isReady()) {
            //Thread.yield();  // jvm updates variables on sleeping thread sometimes 
        }
        System.out.println("from class: " + number);
    }
}



public static void main ( String [] arguments ) throws InterruptedException
{
    System.out.println("start");
    Thread.sleep(3000);

    ready = false;
    number = 23;

    System.out.println("inited variable");
    Thread.sleep(3000);

    new ReaderThread().start();

    System.out.println("thread started");
    Thread.sleep(3000);

    number = 42;
    ready = true;

    System.out.println("variables changed");
    Thread.sleep(3000);


    System.out.println("ended;: " + number);
    Thread.sleep(8000);
    System.out.println("end" + number);

}
}

This variant give me "from class: " message. Like as

private static volatile boolean ready;
...
while (!ready) {
    ...
}

What is the difference in terms of code execution? I know that "synchonized" means "one thread access", and volatile means "get value from main thread without caching"

But why is the behavior of two variants is same??

like image 814
Tres Avatar asked Mar 06 '26 14:03

Tres


2 Answers

Is the synchronized getter method equals with volatile private variable?

No.

The equivalence is with a synchronized setter AND a synchronized getter versus a volatile private variable.

If you use a synchronized getter, and a plain (non-synchronized) setter, there will be no happens-before relationship between one thread's write and another thread's (subsequent) read of the variable.

The other point is that the getter and setter need to synchronize on the same thing.

Finally, a getter or setter may do something more complicated than reading or writing a variable. In that case, the synchronized construct ensures that all of the actions are performed atomically with respect to other threads synchronizing on the same lock. By contrast, a volatile variable cannot give you an atomicity guarantee.


But why is the behavior of two variants is same?

You got lucky!

The Java Memory Model says when a read operation is guaranteed to see the result of a previous read operation. If you do it the right way your application will behave correctly.

The converse is not the case. If you do it wrong, you may get the correct behavior anyway(!) but it is not guaranteed:

  • You may always get it on a particular platform; e.g. hardware with a given number of cores and given memory architecture.

  • You may always get it with a given version of Java.

  • Or you may get the correct behavior ... except in rare or unusual circumstances.

But there are no behavioral guarantees if you don't do what the Java Memory Model requires.


A couple of consequences:

  • Testing won't prove that your correct concurrent code is correct. At best, it may show that it is incorrect.

  • Testing to prove that incorrect concurrent code is incorrect is also difficult. You may find that your incorrect code seems to work correctly.

like image 146
Stephen C Avatar answered Mar 08 '26 03:03

Stephen C


Only releasing and subsequently acquiring lock establishes happens-before relation. So you need to use synchronized method for both getting and setting value fro a variable ready.

But in your example making ready volatile is enough as setting new value fro variable and getting value from variable also establish happens-before.

The main thing is that you need to be consistent. If you use synchronized methods for variable then all access to that variable should be done via those synchronized methods only.

Example in your question will always work predictably with volatile but with only setter marked as synchronized there is no happens-before between

ready = true;

in main thread and

while (!isReady()) 

in second thread. So JVM memory model guarantees nothing here. It might work as you expect it might work not the way you expect.

like image 21
Ivan Avatar answered Mar 08 '26 02:03

Ivan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!