henrycharles
henrycharles

Reputation: 1041

thread synchronization and volatile keyword

I know there is lot of topic is available in stack overflow but as I trying to learn about volatile keyword theoretically i believe its clear to me but when i tried running the following example my understanding is failed or i am not able to visualize the sequence.

Understanding of volatile->Making variable as volatile for an instance, makes it non cacheable for threads that means whichever thread is accessing the volatile variable it has to flush the changes into the main memory immediately so that changes should be visible to other thread.

But in this example if you see the output when threadA write the value as 6 being count as volatile it should be flushed into main memory so when thread B see this changes it should see the changes but thread B is showing 2 instead of 6 or 7

I am not able to visualize the thread can you please help me to visualize how thread execution happens.

public class PerfectExampleToUnderstandVolatile {
    public static void main(String[] args) {

        ThreadSample sample = new ThreadSample();
        Thread thread = new Thread(sample,"threadA");
        Thread thread1 = new Thread(sample,"threadB");
        Thread thread2 = new Thread(sample,"threadC");
        thread.start();
        thread1.start();
        thread2.start();
    }
}

class ThreadSample implements Runnable {
        volatile int count;

    public ThreadSample() {

    }

    @Override
    public void run() {
        while (count < 15) {
            System.out.println(Thread.currentThread().getName() + " " + count);
            count++;
        }

    }

}

Output

**threadA 0**
threadA 1
threadA 2
threadA 3
threadA 4
threadA 5
**threadA 6** at this point thread A writes 6 
**threadB 0** so here thread B should show 6 
threadA 7
**threadC 6** same should be here
threadC 9
threadA 10
threadB 11
threadB 13
threadB 14
threadA 12
threadC 11

Upvotes: 1

Views: 133

Answers (3)

Limestone
Limestone

Reputation: 51

  1. Problem with thread scheduling, between the thread calls System.out.println() with counter value and value prints on console other threads which increases the counter could run

  2. Your loop executed 17 times instead of 15 because lack of synchronization. Volatile guarantees only visibility, synchronization guarantees visibility and mutual exclusion. As you are doing count++, which is compound action (read-increment-write), should use synchronization and as AdamSkywalker suggested AtomicInteger is your friend in this scenario.

Upvotes: 0

rcde0
rcde0

Reputation: 4480

volatile is Not Always Enough

Even if the volatile keyword guarantees that all reads of a volatile variable are read directly from main memory, and all writes to a volatile variable are written directly to main memory, there are still situations where it is not enough to declare a variable volatile.

In fact, multiple threads could even be writing to a shared volatile variable, and still have the correct value stored in main memory, if the new value written to the variable does not depend on its previous value. In other words, if a thread writing a value to the shared volatile variable does not first need to read its value to figure out its next value.

As soon as a thread needs to first read the value of a volatile variable,which happens in above example, and based on that value generate a new value for the shared volatile variable, a volatile variable is no longer enough to guarantee correct visibility. The short time gap in between the reading of the volatile variable and the writing of its new value, creates a race condition where multiple threads might read the same value of the volatile variable, generate a new value for the variable, and when writing the value back to main memory - overwrite each other's values.

The situation where multiple threads are incrementing the same counter is exactly such a situation where a volatile variable is not enough.

Upvotes: 0

AdamSkywalker
AdamSkywalker

Reputation: 11619

There are no contradictions in the output:

  • Thread B can start, see that count is 0, build a string "threadB 0" and go to 'sleep'. Then, when he awakens, he prints it to console (though real count value is 6 by that moment)

  • Thread C can do exactly the same with 6 instead of 0.

Also, increment operation count++ is not atomic, count++ is equal to

int temp = count + 1;
count = temp;

In case if two threads increment count simultaneously, it is possible that value would be incremented by 1, not by 2. That's why you should not use increment operation on volatile variable, use AtomicInteger instead.

Upvotes: 7

Related Questions