0

I am trying to write a simple code to understand volatile keyword in java.

The idea is to increment the value of count field of Runner class using two threads. Helper class implements Runnable where run method increments the count which both static and volatile.

        class Helper implements Runnable{

            @Override
            public void run() {

                for(int i=0; i<100000;i++){         
                    Runner.count+=1;
                }

            }
        }


        public class Runner {

            public static volatile long count=0; // to be incremented

            public static void main(String[] args){

                Thread t1 = new Thread( new Helper()); 
                Thread t2 = new Thread( new Helper());

                t1.start();
                t2.start();

                try {
                    t1.join();
                    t2.join();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                System.out.println("Count= "+count); // output expected to be 200000
            }

        }

The expected output for every run is Count= 200000 , but sometimes i get a different number. Please help me understand how is that possible

Ric K
  • 648
  • 1
  • 6
  • 16
  • Volatile provides visibility, but not atomicity (which is what a compound operation such as variable increment requires). – Kayaman Mar 30 '15 at 07:41

2 Answers2

4

The effect of the volatile keyword is approximately that each individual read or write operation on that variable is atomic.

Notably, however, an operation that requires more than one read/write -- such as i++, which is equivalent to i = i + 1, which does one read and one write -- is not atomic, since another thread may write to i between the read and the write.

Pandiri
  • 313
  • 1
  • 4
3
Runner.count+=1;

means:

Runner.count = Runner.count + 1;

or, in other words:

  1. Get the value of Runner.count.
  2. Add 1 to this value.
  3. Store the new value in Runner.count.

Thread A and B could both get the value of Runner.count (so they both get 1), and then both add 1 to it at the same time (so they both get 2), and then both store it back at the same time (so the new value is 2) - and now the value went from 1 to 2, and not 1 to 3, even though two threads incremented it!

user253751
  • 57,427
  • 7
  • 48
  • 90