Volatile keyword does not work as expected with multiple instances of a class

This question already has an answer here:

  • Why volatile is not working properly 6 answers

I have read in almost all the posts that volatile (even if it's not static) variable is shared among the the threads. When one thread updates the variable then second thread gets the updated value. However when I run below code on my local machine, running java 7 . It is not giving expected results

Code -

public class StatciVolatile3 { public static void main(String args[]) { new ExampleThread2("Thread 1 ").start(); new ExampleThread2("Thread 2 ").start(); } } class ExampleThread2 extends Thread { private volatile int testValue = 1; public ExampleThread2(String str) { super(str); } public void run() { for (int i = 0; i < 3; i++) { try { System.out.println(getName() + " : " + i); if (getName().compareTo("Thread 1 ") == 0) { testValue++; System.out.println("Test Value T1: " + testValue); } if (getName().compareTo("Thread 2 ") == 0) { System.out.println("Test Value T2: " + testValue); } Thread.sleep(1000); } catch (InterruptedException exception) { exception.printStackTrace(); } } } }

And the result is -

Thread 2 : 0 Test Value T2: 1 Thread 1 : 0 Test Value T1: 2 Thread 2 : 1 Test Value T2: 1 Thread 1 : 1 Test Value T1: 3 Thread 2 : 2 Test Value T2: 1 Thread 1 : 2 Test Value T1: 4

Here as we can see for Thread T2 the test value is always 1. Can someone please help me in understanding why is this happening?

Thanks in advance!

My expected result is - That is both the threads are seeing updated value

Thread 1 : 0 Test Value T1: 2 Thread 2 : 0 Test Value T2: 2 Thread 1 : 1 Test Value T1: 3 Thread 2 : 1 Test Value T2: 3 Thread 1 : 2 Test Value T1: 4 Thread 2 : 2 Test Value T2: 4

-------------Problems Reply------------

testValue is an instance variable, so there's a separate copy of the variable for each instance of the class. You've created two instances:

new ExampleThread("Thread 1 ").start();
new ExampleThread("Thread 2 ").start();

... and each has their own copy of the variable. Thread 2 never updates its value, which is why it stays at 1.

If you want them to share the same variable, make it static:

private static volatile int testValue = 1;

Your statement:

I have read in almost all the posts that volatile (even if it's not static) variable is shared among the the threads

... demonstrates a misreading or misunderstanding of what you have read. Changes to a volatile variable will be seen between threads if they both access that same variable, but that does not mean that an instance variable will be shared between instances.

Some comments point out that 'testValue++' is not an atomic operation. In general, it's true that you should avoid this kind of operation on a volatile variable that you're sharing between threads. For your limited example, however, this is not actually a concern, since only one thread actually mutates the value of the variable.

I have read in almost all the posts that volatile (even if it's not static) variable is shared among the the threads

That's an incorrect statement. A volatile instance variable is not shared among threads. A volatile instance variable of a class ensures that all threads that share the same instance of a class will always see the updated value of the volatile instance variable of the class instead of reading the value from the cache.

To fix your problem for the specific code sample posted in your question, you can mark testValue as static.

That being said, volatile does not guarantee atomicity. The operation testValue++; is not atomic so declaring testValue as static wouldn't solve the problem if more than one thread can execute testValue++ (which is not possible in your current example). One way to solve the issue when more than one thread can execute testValue++ would be to declare testValue as an AtomicIntegerand mark it as static

The volatile keyword determines whether the variable will be thread-cached locally or not.

In your example, the result you are expecting is not coming because both the threads are working on independent instances of the testValue parent object (in this case ExampleThread2 objects). If testValue would've been static, then the result would be as you expect.

In multi CPU environment, if two threads, running on different CPUs, access the same object, they will create two separate local caches. Thus, the read/write operation will be ambiguous. In this scenario volatile comes into picture.

When we use volatile, the cache is not created locally, and both the threads (running on different CPUs) will work on the same updated copy (Of course synchronization is needed as applicable).

Category:java Views:8 Time:2018-09-12

Related post

Copyright (C) dskims.com, All Rights Reserved.

processed in 0.220 (s). 11 q(s)