I was running an experiment on different approaches to deal with race condition in multi-threaded java applications . Strategies like atomic variables, synchronize worked well , but I dont see the issue being solved when using volatile variables. Here the code and output for reference.
Can you please guide on what could be the reason for the volatile variable to still lead to a race condition?
package com.shyam.concurrency; public class main { public static void main(String[] args) { demoClass dm1 = new demoClass(); Thread th1 = new Thread(()->{ int i =0; do { i++; dm1.setCounter(); dm1.setAtomicCounter(); dm1.setSyncCounter(); dm1.setVolatileCounter(); } while (i < 100000); }); Thread th2 = new Thread(()->{ int i =0; do { i++; dm1.setCounter(); dm1.setAtomicCounter(); dm1.setSyncCounter(); dm1.setVolatileCounter(); } while (i < 100000); }); th1.start(); th2.start(); try { th1.join(); th2.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Normal counter(Race condition) : " + dm1.getCounter() ); System.out.println("Synchronized counter is :" + dm1.getSyncCounter()); System.out.println("Atomic counter is :" + dm1.getAtomicCounter()); System.out.println("Volatile counter is :" + dm1.getVolatileCounter()); The code that has the increment logic is here:
package com.shyam.concurrency; import java.util.concurrent.atomic.AtomicInteger; public class demoClass { private int counter ; private int syncCounter; private volatile int volatileCounter = 0; private AtomicInteger atomicCounter = new AtomicInteger() ; public int getAtomicCounter() { return atomicCounter.intValue(); } public void setAtomicCounter() { this.atomicCounter.addAndGet(1); } public int getCounter() { return counter; } public void setCounter() { this.counter++; } public synchronized int getSyncCounter() { return syncCounter; } public synchronized void setSyncCounter() { this.syncCounter++; } public int getVolatileCounter() { return volatileCounter; } public void setVolatileCounter() { this.volatileCounter++; } } And here's the output i get:
Normal counter(Race condition) : 197971 Synchronized counter is :200000 Atomic counter is :200000 Volatile counter is :199601
volatiledoesn't provide it, while the other two methods you mention do. So it's just a matter of choosing the correct approach for your problem.volatilewell known to not help with that sort of access. It doesn't work because the spec says it won't.volatilevariable is not an atomic operation. Two threads can interleave such that one is reading while the other is incrementing or other ways. If you need atomicity, you can't choose an operation that only guarantees visibility.