My goal is to understand how the volatile keyword works.
My expected result: The assertEquals did not fail.
My actual result: The assertEquals fail. (sometimes the actual count value are between 9991 to 9999).
I am assuming this happens because of the increment operators / count++
equals to
public void increment() {
int temp = count;
count = temp + 1;
}
and considering that, the temp
attribute is stored thread-locally. Am I true?
Counter.java
public class Counter implements Runnable {
private volatile int count = 0;
public int getCount() { return count; }
public void increment() { count++; }
@Override
public void run() { increment(); }
}
CounterTest.java
public class CounterTest {
@Test
void increment() {
ExecutorService service = Executors.newFixedThreadPool(10);
Counter counter = new Counter();
for (int i = 0; i < 10000; i++) {
service.execute(counter);
}
service.shutdown();
service.awaitTermination(1, TimeUnit.SECONDS);
assertEquals(10000, counter.getCount());
}
}
Operations you perform locally will not have visibility or interference issues by other threads so it does not make sense to declare local variable volatile.
Volatile keyword is used to modify the value of a variable by different threads. It is also used to make classes thread safe. It means that multiple threads can use a method and instance of the classes at the same time without any problem. The volatile keyword can be used either with primitive type or objects.
volatile is unnecessary and useless for synchronization between threads. Threading libraries can't be implemented in terms of volatile ; it has to rely on platform-specific details anyway, and when you rely on those, you no longer need volatile .
Therefore, the volatile keyword does not provide thread safety when non-atomic operations or composite operations are performed on shared variables. Operations like increment and decrement are composite operations.
My goal is to understand how the volatile keyword works
If that is your goal, then start looking at the JLS
and the guarantees that volatile
offers. volatile
is not about atomic operations, i.e.: count++;
is not atomic. As such, this :
assertEquals(10000, counter.getCount());
can fail, at any point in time.
volatile
is about what some thread is supposed to "observe" when it has observed a written value to that variable, by another thread. There are many, literally many examples of what this means, probably the most famous one is this. Start there and build your knowledge up to the JLS
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With