Niklas has posted 30 posts at DZone. You can read more from them at their website. View Full User Profile

Threading stories: volatile and synchronized

10.27.2011
| 4855 views |
  • submit to reddit

In my last blog about the volatile modifier I have introduced a little program that illustrates the behaviour of volatile in a Java 6 (26) Hotspot VM. Since that day I had some interesting discussions that I wanted to share in this blog. It adds another valuable insights on the volatile modifier.

Here is my little program, which I have adopted a little to make it easier. My previous example was originally thought as a thread contention example, which will be the topic in one of my upcoming posts.

import java.util.Timer;
import java.util.TimerTask;

public class AnotherVolatileExampleA {

 private volatile boolean expired = false;
 private long counter = 0;
 private Object mutex = new Object();

 private class Worker implements Runnable {
  @Override
  public void run() {
   synchronized (mutex) {
    final Timer timer = new Timer();
    timer.schedule(new TimerTask() {
     public void run() {
      expired = true;
      System.out.println("Timer interrupted main thread ...");
      timer.cancel();
     }
    }, 1000);
    while (!expired) {
     counter++; // do some work
    }
    System.out.println("Main thread was interrupted by timer ...");
   };
  }
 }

 public static void main(String[] args) throws InterruptedException {
  AnotherVolatileExampleA volatileExample = new AnotherVolatileExampleA();
  Thread thread1 = new Thread(volatileExample.new Worker(), "Worker-1");
  thread1.start();
 }
}

Now, this program still behaves similar like the one of my last blog. With volatile in line 6 the result written to the console is:

Timer interrupted main thread ...
Main thread was interrupted by timer ...

Without volatile in line 6 the result is:

    Timer interrupted main thread ...  


One question in a discussion was, why that happens although everything takes place in a synchronized block. The Java VM specification says the synchronized keywork garantees that (less formal!) a variable is written into the memory heap and is read from the memory heap (read here). Now, this is true, but it's missing the point that the thread only needs to read the variable ONCE within a single synchronized block. In the example above the expired variable is read once at the very first while loop. Afterwards the thread does not need to read the variable again. Consider this program:

import java.util.Timer;
import java.util.TimerTask;

public class AnotherVolatileExampleB {

 private boolean expired = false;
 private long counter = 0;
 private Object mutex = new Object();

 private class Worker implements Runnable {
  @Override
  public void run() {
   final Timer timer = new Timer();
   timer.schedule(new TimerTask() {
    public void run() {
     expired = true;
     System.out.println("Timer interrupted main thread ...");
     timer.cancel();
    }
   }, 1000);
   boolean tmpExpired = false;
   while (!tmpExpired) {
    synchronized (mutex) {
     tmpExpired = expired;
    }
    counter++; // do some work
   }
   System.out.println("Main thread was interrupted by timer ...");
  }
 }

 public static void main(String[] args) throws InterruptedException {
  AnotherVolatileExampleB volatileExample = new AnotherVolatileExampleB();
  Thread thread1 = new Thread(volatileExample.new Worker(), "Worker-1");
  thread1.start();
 }
}

  In that case the synchronized block is within the while loop (lines 23-25) and the thread is now forced to re-read the expired variable from the main memory in each loop 'cause synchronized garantees to read from memory once (same applies to Java 5 locks). The result of that program will be as expected from a synchronized block:

Timer interrupted main thread ...
Main thread was interrupted by timer ...

 

Therefore, if you wish to read a variable from memory in a synchronized block (or within a Java 5 lock), remember that the thread only garantees to read the variable once from the memory heap. The volatile modifier, on the other hand, always garantees a "memory heap read" (see here).

From http://niklasschlimm.blogspot.com/2011/10/threading-stories-volatile-and.html

Published at DZone with permission of its author, Niklas Schlimm.

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

Tags:

Comments

Vinay Sambyal replied on Fri, 2011/10/28 - 4:38am

Hi Niklas, i see the same results in first piece of code. irrespective of volatile being used or not. It should not be though. Running the sample in eclipse JRE 1.6.20. Timer interrupted main thread ... Main thread was interrupted by timer ... Cheers

Niklas Schlimm replied on Fri, 2011/10/28 - 5:44am

Try -server vm option in run configurations ... Cheers, Niklas

Vinay Sambyal replied on Fri, 2011/10/28 - 10:24am in response to: Niklas Schlimm

thanks Niklas. Did not work for me :(. I will levae it for now. Tried setting -server VM option in eclipse, passing as param etc etc. It is 32 bit machine that I am working on. worked as expected. seems like jre installation was a custom one.

Stig Christensen replied on Sat, 2011/10/29 - 8:03am

Are you sure about that? I have not run the code, but isn't more likely it is because that the timer thread is not running in a synchronized scope?

Stefan Zobel replied on Sat, 2011/10/29 - 5:34pm in response to: Stig Christensen

+1 Stig's observation is correct. Your "theory", however, is simply made up.

Stig Christensen replied on Sun, 2011/10/30 - 4:14am

in your code without volatile, your timer thread should synchronize on mutex and your other thread should look something like this (to prevent dead locks)

boolean running = true;
while (running) {
synchronized (mutex) {
running = expired;
 }
counter ++;
}

Niklas Schlimm replied on Sun, 2011/10/30 - 5:45am

Hi guys, my blog wasn't concerned about thread synchronization and dead locks. It's concerned about: - the fact that synchronized does not affect the threads local data cache (expired value is cached during the while loop, evidence: volatile changes program behaviour) - the need to declare variables volatile if you like to reread values from the memor heap Therefore its difficult for me to follow your arguments to be honest :) Of course, I did not have a 100% bullet proof evidence. Its the conclusions I draw from the program behaviour when I change the parameters and from what I read from the jvm spec. Cheers, Niklas

Stig Christensen replied on Sun, 2011/10/30 - 6:54am

.. still AnotherVolatileExampleB is error prone and could end up with an infinity loop. And AnotherVolatileExampleA is using volatile so you should remove the synchronization.

Niklas Schlimm replied on Sun, 2011/10/30 - 9:32am

Again, you're missing the point. That you don't get me wrong, I welcome you're thoughts, but the code was not meant to demonstrate bullet proof multithreaded programming. It's about java memory model and therefore the code is perfectly surving its purpose. Cheers, Niklas

Comment viewing options

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