Synchronization in Java

What Is a Thread?

In the field of computer science, a thread refers to a sequential set of instructions embedded within a program, capable of executing autonomously without reliance on other code segments. Within a program, numerous threads can operate concurrently, running in parallel.

Every Java program encompasses a minimum of one thread, commonly referred to as the main thread. This primary thread is established by the JVM during the program's initiation, specifically when the main() method is invoked. The main thread exists as an individual entity, possessing distinct registers, a stack, and a code segment, enabling it to execute in parallel with other threads encompassed within a process—a compilation of multiple threads.

What Is Multithreading?

Multithreading is a fundamental concept in computer science that involves the simultaneous execution of multiple threads. It harnesses the power of two or more distinct "threads" of execution, collaborating harmoniously to achieve a specific objective. Each sequence of instructions possesses its own distinctive flow of control, completely detached from the execution paths of other threads.

Synchronization in Java

In general, synchronization is employed to safeguard resources that are accessed concurrently. One of the advantages of utilizing multiple threads in an application is their ability to execute asynchronously. However, there are scenarios where multiple threads need to share access to shared objects. Consider a database system, where it is undesirable for one thread to update a database record while another thread is attempting to read it. In such cases, it is crucial to ensure that a resource is accessed by only one thread at a time. Otherwise, multiple threads might access the same resource simultaneously, oblivious to each other's actions.

Java provides mechanisms to coordinate the actions of multiple threads using synchronized methods and synchronized statements. The synchronized keyword is used to declare methods that require coordinated access to an object. Only one synchronized method can be invoked for an object at any given point in time. This prevents conflicts between synchronized methods across multiple threads. The synchronized statement is another construct that facilitates synchronization. Its general form is as follows:

Syntax
synchronized(objectidentifier) { // Access shared variables and other shared resources }

The objectidentifier parameter in the synchronized statement refers to a reference of an object whose lock is associated with the monitor represented by the synchronized statement. In Java, there are two fundamental synchronization idioms available: synchronized methods and synchronized statements.

What are synchronized methods and synchronized statements?

Synchronized Methods

Synchronized methods facilitate a straightforward approach to safeguarding against thread interference and memory consistency errors by ensuring that when multiple threads have access to an object, all operations involving that object's variables are conducted exclusively through synchronized methods. Consequently, the occurrence of interleaving two invocations of synchronized methods on the same object becomes impossible.

When a particular thread executes a synchronized method pertaining to an object, any other threads that invoke synchronized methods on the same object are impeded (temporarily suspended) until the initial thread completes its interaction with the object. To designate a method as synchronized, it is merely necessary to include the synchronized keyword in its declaration.

public synchronized void increament(){ count++; }

Synchronized block

Synchronization blocks ensure the atomicity of a group of code statements. They are useful when you need to synchronize access to an object of a class or when you want only a specific portion of a method to be synchronized with respect to an object. By using a synchronized block, you can achieve this level of synchronization.

public void add(int value){ synchronized(this){ this.count += value; } }

A notable distinction between synchronized methods and blocks is that synchronized blocks generally reduce the scope of the lock. Since the scope of the lock is inversely proportional to performance, it is preferable to lock only the critical section of code. Additionally, synchronized blocks have the potential to throw a java.lang.NullPointerException if the expression provided as a parameter to the block evaluates to null. This is not the case with synchronized methods.

Conclusion

Synchronization in Java ensures thread safety and prevents concurrent access issues by allowing only one thread at a time to access synchronized blocks or methods.