Memory Consistency Error in Java

JavaServer Side ProgrammingProgramming

When the concept of multithreading is implemented, it is possible that changes made by one thread wouldn’t be visible to the other thread. This indicates that the view of each thread is inconsistent with respect to each other. This is known as memory consistency error.

CPU might initiate main memory access in a different order, whereas the threads might access them in a different order.

This is usually true when write operation is being performed, thereby avoiding the CPU wait time.

The write operation is an atomic one, meaning no other operation would be performed by other threads when a write operation is being performed.

In addition to this, the order in which write operation is performed will be consistently maintained for every associated CPU, whereas the CPUs can understand the write times of other CPUs in a different manner. This phenomenon could lead to memory inconsistency.

How can memory inconsistency errors be avoided?

A happens-before relationship needs to be established so that memory write is performed by a single thread, and this is visible to read operations performed by other thread on the same memory.

The ‘start’ function and the ‘join’ function are considered as happens-before relationship. The ‘start’ function makes sure that the newly created thread is visible. The ’join’ function makes sure that the thread that is visible is joined to the other thread.

Example

 Live Demo

import java.io.*;
class class_shared{
   static int m=2;
   void inc(){
      for(int j=0;j<5;j++){
         m = m+1;
         System.out.println("After its increment is "+m);
      }
   }
   void dec(){
      for(int j=0;j<5;j++){
         m = m-1;
         System.out.println("After its decrement is "+m);
      }
   }
}
public class Demo{
   public static void main(String[] args){
      final class_shared my_inst = new class_shared();
      Thread my_t_1 = new Thread(){
         @Override
         public void run(){
            my_inst.inc();
         }
      };
      Thread my_t_2 = new Thread(){
         @Override
         public void run(){
            my_inst.dec();
         }
      };
      my_t_1.start();
      my_t_2.start();
   }
}

Output

After its increment is 3
After its decrement is 2
After its decrement is 2
After its decrement is 1
After its increment is 3
After its decrement is 0
After its increment is 1
After its increment is 1
After its decrement is 0
After its increment is 2

A class named ‘class_shared’ defines a static value, and a void function, that iterates over a set of numbers, and increments it and displays it on the console. Another function named ‘dec’ iterates over a set of numbers and decrements every time and displays the output on the console. A class named Demo contains the main function that creates an instance of the class, and creates a new thread. This thread is overridden, and the run function is called on this object instance. Same thing is done for the second thread too. Both these threads are then called with the ‘start’ function.

raja
Published on 14-Jul-2020 06:47:57
Advertisements