views:

100

answers:

3

Using volatile on a variable reduces the risk of memory consistency error (Please correct me if this reveals some holes in my understanding of any relevant concept). So in the following example even though the variable c1 is volatile, still the occurrence of memory constancy error results in c1 becoming 15 or sometimes 14 in the output rather then the correct output 16.

class Lunch implements Runnable {

    private volatile long c1 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();
    public void inc1() {
       // synchronized(lock1) { c1 is volatile
            c1++;
       // }
    }

    public void run() {
        try {
            inc1();
            Thread.sleep(1000);
            inc1();
            Thread.sleep(1000);
            inc1();
            Thread.sleep(1000);
            inc1();
            inc1();
            Thread.sleep(1000);
            inc1();
            Thread.sleep(1000);
            inc1();
            Thread.sleep(1000);
            inc1();
        }
        catch(InterruptedException e) {
            return;
        }
    }
    public long value() {
        return c1;
    }
    public static void main(String args[]) throws InterruptedException {
        Lunch l = new Lunch();
       Thread t1 = new Thread(l);
       Thread t2 = new Thread(l);
       t1.start();
       t2.start();
       t1.join();
       t2.join();
       System.out.println(l.value());
    }
} 
+6  A: 

You are correct. Because ++ is NOT an atomic operation you can still get inconsistent results where a thread reads/increments/writes a value at the same time as another thread.

Consider using AtomicInteger for cases like this.

Mike Q
So if I replace multiple invocations of increment() in run() with another function update(long c1) { this.c1 = c1 } which is a part of this class. Then since c1 is volatile and ++ is not involved, the result should be consistently correct?
msk
Or `AtomicIntegerUpdater` in some circumstances where load-manipulate-store operations are rare.
Tom Hawtin - tackline
@msk it would be "correct" in that at any point in time any thread reading c1 would be guaranteed to see the up to date value of c1. The usefulness of information that is set without being checked beforehand is often questionable. The usual use-case is a boolean flag where one thread is signalling another (like a stop flag). This is pretty much the only case where I use volatile.
Mike Q
+1  A: 

Check http://www.javabeat.net/tips/169-volatile-keyword-in-java.html for understanding what volatile does. It avoids the intermediate thread cache but anyway there can be the lossed update from reading its value and updating in a non atomic operation.

helios
+3  A: 

Atomicity is only part of the picture. There is also visibility. If a non-volatile (and non-synchronized) variable value is changed, other threads are not guaranteed to see the change in time, or at all.

Péter Török