Observability Done Right: Best Practices and Anti-Patterns for Effective System Monitoring

Image
  WHAT Observability is a concept that refers to the ability to gain insights into the behavior and performance of complex systems. In the context of software engineering, observability involves the collection, analysis, and visualization of data from software applications, infrastructure, and other components of a system. In the animal kingdom, observability plays a critical role in survival, allowing animals to monitor their surroundings, detect threats, and find food. Dolphins use echolocation to observe their surroundings. They emit high-frequency sounds that bounce off objects, allowing them to create a 3D map of their environment. Thanks for reading Knowledge Cafe! Subscribe for free to receive new posts and support my work. Subscribed WHY In today's era, architectures are becoming increasingly large, complex, and fast-paced due to the faster development and deployment of software by distributed teams with the help of DevOps, continuous delivery, and agile development methodo...

Race Condition in Java

Race condition in Java is a type of concurrency bug or issue which is introduced in your program because  parallel execution of your program by multiple threads at same time, Since Java is a multi-threaded programming language hence risk of Race condition is higher in Java which demands clear understanding of what causes a race condition and how to avoid that. Anyway Race conditions are just one of hazards or riskpresented by  use of multi-threading in Java just like deadlock in Java. Race conditions occurs when two thread operate on same object without proper synchronization and there operation interleaves on each other. Classical example of Race condition is incrementing a counter since increment is not an atomic operation and can be further divided into three steps like read, update and write. if two threads tries to increment count at same time and if they read same value because of interleaving of read operation of one thread to update operation of another thread, one count will be lost when one thread overwrite increment done by other thread. atomic operations are not subject to race conditions because those operation cannot be interleaved.

How to find Race Conditions in Java


Finding Race conditions in any language is most difficult job and Java is no different, though since readability of Java code is very good and synchronized constructs are well defined heaps to find race conditions by code review. finding race conditions by unit testing is not reliable due to random nature of race conditions. since race conditions surfaces only some time your unit test may passed without facing any race condition. only sure shot way to find race condition is reviewing code manually or using code review tools.


Code Example of Race Condition in Java


Based on my experience in Java synchronization and where we use synchronized keyword I found that two code patterns namely "check and act" and "read modify write" can suffer race condition if not synchronized properly. both cases rely on natural assumption that a single line of code will be atomic and execute in one shot which is wrong e.g. ++ is not atomic.


"Check and Act" race condition pattern

classical example of "check and act" race condition in Java is getInstance() method of Singleton Class, remember that was one questions which we have discussed on 10 Interview questions on Singleton pattern in Java as "How to write thread-safe Singleton in Java". getInstace() method first check for whether instance is null and than initialized the instance and return to caller. Whole purpose of Singleton is that getInstanceshould always return same instance of Singleton. if you call getInstance() method from two thread simultaneously its possible that while one thread is initializing singleton after null check, another thread sees value of _instance reference variable as null (quite possible in java) especially if your object takes longer time to initialize and enters into critical section which eventually results in getInstance() returning two separate instance of Singleton. This may not happen always because a fraction of delay may result in value of _instance updated in main memory. here is a code example


 if(obj == null) 
obj = new OnlyOne();

 Good Code
synchronized(this) 
{
if(obj == null)
obj = new OnlyOne();
}

read-modify-update race conditions


This is another code pattern in Java which cause race condition, classical example is the non thread safe counter we discussed in how to write thread safe class in Java. this is also a very popular multi-threading question where they ask you to find bugs on concurrent code. read-modify-update pattern also comes due to improper synchronization of non-atomic operations or combination of two individual atomic operations which is not atomic together e.g. put if absent scenario. consider below code

counter++

this is not a atomic operation, it has 3 steps: 1. get the value 2. increase the value 3. assign to the value

Java Program to demonstrate Racing condition
package in.softcare;

public class ThreadDemo implements Runnable {

private int x = 0;

public int getValue() throws InterruptedException {

for (int i = 0; i < 8000; i++) {
x = i + 1;
if (x % 50 == 0)
Thread.sleep(2);
}

return x;
}

@Override
public void run() {

try {
System.out.println(Thread.currentThread().getName() + "-"
+ getValue());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}

 
package in.softcare;

public class ThreadTesting {
public static void main(String args[]) {
ThreadDemo t1 = new ThreadDemo();

Thread th1 = new Thread(t1);
Thread th2 = new Thread(t1);
Thread th3 = new Thread(t1);
Thread th4 = new Thread(t1);
th1.setName("First Thread");
th2.setName("Second Thread");
th3.setName("Third Thread");
th4.setName("Fourth Thread");

th1.start();
th2.start();
th3.start();
th4.start();
}

}

OUTPUT:
Fourth Thread-7850
First Thread-7950
Third Thread-7950
Second Thread-8000

Above Output is not constant always, it depends on OS and memory allocation of processor.

 

Popular posts from this blog

Chain of responsibility using Spring @Autowired List

Iterate Through a HashMap

Under the Hood: Understanding the Gossip Protocol in Apache Cassandra