Difference Between Atomic, Volatile and Synchronized in Java
Last Updated :
17 Nov, 2021
Synchronized is the modifier applicable only for methods and blocks but not for the variables and for classes. There may be a chance of data inconsistency problem to overcome this problem we should go for a synchronized keyword when multiple threads are trying to operate simultaneously on the same java object. If a method or block declares as synchronized then at a time only one thread at a time is allowed to execute that method or block on the given object so that the data inconsistence problem will be resolved. The main advantage of synchronized keywords is we can resolve data inconsistence problems but the main disadvantage of this keyword is it increases the waiting time of the thread and creates performance problems. Hence, It is not recommended using, the synchronized keyword when there is no specific requirement. Every object in java has a unique lock. The lock concept will come into the picture when we are using a synchronized keyword.
The remaining threads are not allowed to execute any synchronized method simultaneously on the same object when a thread executing a synchronized method on the given object. But remaining threads are allowed to execute the non-synchronized method simultaneously.
Volatile Modifier:
If a value of a variable keeps on changing by multiple threads then there may be a chance of a data inconsistency problem. It is a modifier applicable only for variables, and we can’t apply it anywhere else. We can solve this problem by using a volatile modifier. If a variable is declared as volatile as for every thread JVM will create a separate local copy. Every modification performed by the thread will take place in the local copy so that there is no effect on the remaining threads. Overcoming the data inconsistency problem is the advantage and the volatile keyword is creating and maintaining a separate copy for every thread increases the complexity of the programming and creates performance problem is a disadvantage. Hence, if there are no specific requirements it is never recommended to use volatile keywords.
Atomic Modifier:
If a value of a variable keeps on changing by multiple threads then there may be a chance of a data inconsistency problem. We can solve this problem by using an atomic variable. Data inconsistency problem can be solved when objects of these classes represent the atomic variable of int, long, boolean, and object reference respectively.
Example:
In the below example every thread increments the count variable 5 times. So after the execution of two threads, the finish count value should be 10.
Java
import java.io.*;
import java.util.*;
class myThread extends Thread {
private int count;
public void run()
{
for ( int i = 1 ; i <= 5 ; i++) {
try {
Thread.sleep(i * 100 );
count++;
}
catch (InterruptedException
e) {
System.out.println(e);
}
}
}
public int getCount() { return this .count; }
}
public class GFG {
public static void main(String[] args)
throws InterruptedException
{
myThread t = new myThread();
Thread t1 = new Thread(t, "t1" );
t1.start();
Thread t2 = new Thread(t, "t2" );
t2.start();
t1.join();
t2.join();
System.out.println( "count=" + t.getCount());
}
}
|
If we run the above program, we will notice that the count value varies between 6,7,8.9 The reason is that count++ is not an atomic operation. So by the time one thread read it’s value and increment it by one, another thread has read the older value leading to the wrong result. To solve this issue, we will have to make sure that increment operation on count is atomic.
Below program will always output count value as 8 because AtomicInteger method incrementAndGet() atomically increments the current value by one.
Java
import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
class myThread extends Thread {
private AtomicInteger count = new AtomicInteger();
public void run()
{
for ( int i = 1 ; i <= 5 ; i++) {
try {
Thread.sleep(i * 100 );
count.incrementAndGet();
}
catch (InterruptedException e) {
System.out.println(e);
}
}
}
public AtomicInteger getCount() { return count; }
}
public class GFG {
public static void main(String[] args)
throws InterruptedException
{
myThread t = new myThread();
Thread t1 = new Thread(t, "t1" );
t1.start();
Thread t2 = new Thread(t, "t2" );
t2.start();
t1.join();
t2.join();
System.out.println( "count=" + t.getCount());
}
}
|
Synchronized |
Volatile |
Atomic |
1.It is applicable to only blocks or methods. |
1.It is applicable to variables only. |
1.It is also applicable to variables only. |
2. Synchronized modifier is used to implement a lock-based concurrent algorithm, and i.e it suffers from the limitation of locking. |
2.Whereas Volatile gives the power to implement a non-blocking algorithm that is more scalable. |
2.Atomic also gives the power to implement the non-blocking algorithm. |
3.Performance is relatively low compare to volatile and atomic keywords because of the acquisition and release of the lock. |
3.Performance is relatively high compare to synchronized keyword. |
3.Performance is relatively high compare to both volatile and synchronized keyword. |
4.Because of its locking nature it is not immune to concurrency hazards such as deadlock and livelock. |
4.Because of its non-locking nature it is immune to concurrency hazards such as deadlock and livelock. |
4.Because of its non-locking nature it is immune to concurrency hazards such as deadlock and livelock. |
Share your thoughts in the comments
Please Login to comment...