logologo
  • AI Tools

    DB Query GeneratorMock InterviewResume BuilderLearning Path GeneratorCheatsheet GeneratorAgentic Prompt GeneratorCompany ResearchCover Letter Generator
  • XpertoAI
  • MVP Ready
  • Resources

    CertificationsTopicsExpertsCollectionsArticlesQuestionsVideosJobs
logologo

Elevate Your Coding with our comprehensive articles and niche collections.

Useful Links

  • Contact Us
  • Privacy Policy
  • Terms & Conditions
  • Refund & Cancellation
  • About Us

Resources

  • Xperto-AI
  • Certifications
  • Python
  • GenAI
  • Machine Learning

Interviews

  • DSA
  • System Design
  • Design Patterns
  • Frontend System Design
  • ReactJS

Procodebase © 2024. All rights reserved.

Level Up Your Skills with Xperto-AI

A multi-AI agent platform that helps you level up your development skills and ace your interview preparation to secure your dream job.

Launch Xperto-AI

Synchronization Techniques in Java

author
Generated by
Anushka Agrawal

16/10/2024

Java

Sign in to read full article

Introduction to Synchronization

In modern applications, multithreading is an essential feature that enhances performance by allowing multiple threads to run concurrently. However, concurrent access to shared resources can lead to data inconsistency and unexpected behaviors, known as race conditions. To prevent these scenarios, synchronization techniques become crucial.

This blog will provide a comprehensive overview of various synchronization methods available in Java.

1. Intrinsic Locks (Monitor Locks)

Every object in Java has an intrinsic lock, also known as a monitor. When a thread acquires the lock on an object, all other threads that try to access the same object must wait until the lock is released.

Example:

class Counter { private int count = 0; public synchronized void increment() { count++; } public synchronized int getCount() { return count; } }

In the code above, the increment and getCount methods are synchronized. This ensures that only one thread can execute either of these methods at a time, preventing concurrent modifications to the count variable.

2. Synchronized Blocks

Sometimes, you may want only a part of a method to be synchronized. In such cases, synchronized blocks provide a finer level of control, allowing you to limit the scope of synchronization.

Example:

class SharedResource { private int data; public void updateData(int value) { synchronized(this) { data = value; } } }

Here, only the code within the synchronized block is locked, allowing other parts of the updateData method to execute concurrently without blocking.

3. The volatile Keyword

The volatile keyword in Java signifies that a variable's value may be changed by different threads. Marking a variable as volatile ensures that reads and writes to it are directly read from and written to main memory, thus preventing caching effects.

Example:

class VolatileExample { private volatile boolean running = true; public void stop() { running = false; } public void run() { while (running) { // Do something } } }

In this example, the running variable is marked volatile. Changes made by one thread are immediately visible to other threads, making it perfect for flags that control the execution of threads.

4. Reentrant Locks

Java provides the java.util.concurrent.locks package, which includes the ReentrantLock class. This lock is more flexible than intrinsic locks, allowing features like try-lock and timed lock.

Example:

import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; class LockExample { private Lock lock = new ReentrantLock(); private int count = 0; public void increment() { lock.lock(); try { count++; } finally { lock.unlock(); } } public int getCount() { return count; } }

The above example demonstrates how to utilize ReentrantLock. Here, we explicitly acquire and release the lock using the lock() and unlock() methods, allowing for better handling of exceptions through the finally block.

5. Semaphores

A semaphore is a signaling mechanism that helps control access to a particular resource by multiple threads. In Java, the Semaphore class is used to maintain a set number of permits for resource access.

Example:

import java.util.concurrent.Semaphore; class SemaphoreExample { private final Semaphore semaphore = new Semaphore(2); // Allow 2 threads to access a resource public void accessResource() { try { semaphore.acquire(); // critical section } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { semaphore.release(); } } }

In this example, the semaphore is initialized with a count of 2, allowing two threads to access the critical section concurrently. Other threads will have to wait until a permit becomes available.

6. CountDownLatch

A CountDownLatch is a synchronization aid that allows one or more threads to wait until a set of operations performed by other threads completes. You initialize it with a count, and each time a thread completes its task, it decrements the count.

Example:

import java.util.concurrent.CountDownLatch; class Task implements Runnable { private CountDownLatch latch; public Task(CountDownLatch latch) { this.latch = latch; } @Override public void run() { try { // Simulate some work Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { latch.countDown(); } } } public class CountDownLatchExample { public static void main(String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch(3); for (int i = 0; i < 3; i++) { new Thread(new Task(latch)).start(); } latch.await(); // Wait for the count to reach zero System.out.println("All tasks completed!"); } }

In this example, three tasks are started, and the main thread waits for all tasks to complete before printing a message. The CountDownLatch effectively manages synchronization without requiring excessive locking.

7. CyclicBarrier

A CyclicBarrier allows a set of threads to all wait for each other to reach a common barrier point. Once all threads reach the barrier, they are released simultaneously to continue execution.

Example:

import java.util.concurrent.CyclicBarrier; class Worker implements Runnable { private CyclicBarrier barrier; public Worker(CyclicBarrier barrier) { this.barrier = barrier; } @Override public void run() { System.out.println("Worker is doing some work..."); try { Thread.sleep(1000); // Simulate work barrier.await(); // Wait at the barrier } catch (Exception e) { Thread.currentThread().interrupt(); } System.out.println("Worker has finished work and proceeding..."); } } public class CyclicBarrierExample { public static void main(String[] args) throws Exception { final int NUM_WORKERS = 3; CyclicBarrier barrier = new CyclicBarrier(NUM_WORKERS); for (int i = 0; i < NUM_WORKERS; i++) { new Thread(new Worker(barrier)).start(); } } }

In this illustration, each Worker thread performs some work and waits at the barrier for all workers to finish before continuing. This is perfect for scenarios where tasks can proceed only once all threads are ready.

By utilizing these different synchronization techniques in Java, you can effectively manage multithreading in your applications while ensuring data integrity and preventing race conditions.

Popular Tags

JavaMultithreadingConcurrency

Share now!

Like & Bookmark!

Related Collections

  • Java Essentials and Advanced Concepts

    23/09/2024 | Java

  • Mastering Object-Oriented Programming in Java

    11/12/2024 | Java

  • Spring Boot CRUD Mastery with PostgreSQL

    30/10/2024 | Java

  • Spring Boot Mastery from Basics to Advanced

    24/09/2024 | Java

  • Advanced Java Memory Management and Garbage Collection

    16/10/2024 | Java

Related Articles

  • Mastering Spring Boot and Kafka Integration

    24/09/2024 | Java

  • Understanding Deadlock, Livelock, and Starvation in Java Concurrency

    16/10/2024 | Java

  • Demystifying Java's Modular System

    23/09/2024 | Java

  • Understanding Garbage Collectors in Java

    16/10/2024 | Java

  • Mastering Exception Handling in Java

    23/09/2024 | Java

  • Mastering Spring Boot and MySQL Integration

    24/09/2024 | Java

  • Mastering Java JDBC for Efficient Database Access

    23/09/2024 | Java

Popular Category

  • Python
  • Generative AI
  • Machine Learning
  • ReactJS
  • System Design