Atomic variables in java

Mutable variables shared in a multi threads environments doesn't have constitent state everytime and it is hard to detect concurrency errors.

Let's consider a simple example

public class Counter {
	int counter = 0;
	public void increment() {
		counter++;
	}
}

In above example if multiple threads execute the increment() method at same time, the value may not be incremented that many times. Let's say if two threads execute the method concurrently then increment value can vary between 1 or 2. In reality counter++ is a 3 steps operation done by the CPU. First fetch the current value, then second step is to increment it and third is to write the new value back to memory. Now if two threads call the increment() concurrently both threads might see value of counter as 0 and will increment the value to 1.

Use of synchronization keyword

Thankfully, there is an easy solution to fix the problem. Making the method or block as synchronized with allow only one thread to access it and thus method will behave correctly. This trivial solution comes with a cost and that the performance. The performance is impacted for such code because one thread has to wait for the other thread to finish the execution. When first thread finishes the execution then it will releaes the lock and ohter threads in waiting state will try to acquire the lock. This involves considerable overhead and can impact the performance of the system. Such behavior of acquiring lock and holding to it such that no other thread can access is called Optimistic Locking

public class Counter {
	int counter = 0;
	public void synchronized increment() {
		counter++;
	}
}

Compare-and-swap (CAS) Operation

In computer science, compare-and-swap (CAS) is an atomic instruction used in multithreading to achieve synchronization. It compares the contents of a memory location with a given value and, only if they are the same, modifies the contents of that memory location to a new given value. This is done as a single atomic operation. The atomicity guarantees that the new value is calculated based on up-to-date information; if the value had been updated by another thread in the meantime, the write would fail. The result of the operation must indicate whether it performed the substitution; this can be done either with a simple boolean response (this variant is often called compare-and-set), or by returning the value read from the memory location (not the value written to it).Source Wikipedia

Atomic Variables in Java

Good news is, in java Atomic Variables are built for handling concurrency well. The most commonly used atomic variable classes in Java are AtomicInteger, AtomicLong, AtomicBoolean, and AtomicReference. The main methods exposed by these classes are:

public class Counter {
	final AtomicInteger counter = new AtomicInteger(0);
	public void  increment() {
		while(true) {
			int currentValue = counter.get();
			int newValue = currentValue + 1;
			if(counter.compareAndSet(currentValue, newValue)) {
				return;
			}
		}
	}
}

compareAndSet method gurantees that the value is updated only when it see the currentValue or else it tries infinitely


Recommend Reading

  1. How java manages Memory?
  2. Why is it advised to use hashcode and equals together?
  3. Comparable and Comparator in java
  4. How to create Singleton class in Java?
  5. Difference between equals and ==?
  6. When to use abstract class over interface?
  7. Difference between final, finally and finalize
  8. Why is it recommended to use Immutable objects in Java