What is a real time example of synchronization in Java?

Tanya 188 Published: 08/16/2024

What is a real time example of synchronization in Java?

One of the most common and straightforward examples of synchronization in Java is the Producer-Consumer problem. Imagine you have a shared resource, like a plate of food at a party, where multiple people can take food from it (produce) and multiple people can put food on it (consume). Without proper control, this could lead to chaos: someone might try to take an empty plate or put more food than the plate can hold.

In Java, we use threads to simulate these producers and consumers. Each thread represents a person trying to access the shared resource. The problem arises when multiple threads simultaneously try to read from (consume) or write to (produce) this shared resource.

Here's how you could solve this issue using synchronization in Java:

public class ProducerConsumerExample {

private static final int LIMIT = 10; // Maximum capacity of the plate

private static final int SLEEP_MILLIS = 1000; // Time delay between actions

private static volatile boolean producerShouldRun = true;

private static final Object lock = new Object();

private static volatile int totalFoodOnPlate = 0;

public static void main(String[] args) {

Thread producerThread = new Thread(new Producer());

Thread consumerThread = new Thread(new Consumer());

// Start the threads

producerThread.start();

consumerThread.start();

// Wait for both threads to finish

producerShouldRun = false;

producerThread.join();

consumerThread.join();

}

static class Producer implements Runnable {

@Override

public void run() {

try {

while (producerShouldRun) {

int amountOfFoodToProduce = new Random().nextInt(LIMIT - totalFoodOnPlate) + 1;

synchronized (lock) {

// Check if there's space on the plate before producing

if (totalFoodOnPlate + amountOfFoodToProduce > LIMIT) {

System.out.println("Plate is full. Waiting...");

lock.wait();

}

totalFoodOnPlate += amountOfFoodToProduce;

}

Thread.sleep(SLEEP_MILLIS);

}

} catch (InterruptedException e) {

// Handle the interruption

}

}

}

static class Consumer implements Runnable {

@Override

public void run() {

try {

while (true) {

synchronized (lock) {

// Check if there's food on the plate before consuming

if (totalFoodOnPlate == 0) {

System.out.println("No food left. Waiting...");

lock.wait();

}

int amountOfFoodToConsume = new Random().nextInt(totalFoodOnPlate) + 1;

totalFoodOnPlate -= amountOfFoodToConsume;

}

Thread.sleep(SLEEP_MILLIS);

}

} catch (InterruptedException e) {

// Handle the interruption

}

}

}

}

In this example, totalFoodOnPlate represents the shared resource. The producer thread tries to add more food than the plate can hold if it's already full, while the consumer thread tries to consume food from an empty plate. Both threads are synchronized on the same lock object (lock) before accessing totalFoodOnPlate.

When a thread tries to access totalFoodOnPlate and finds it's in an inconsistent state (e.g., trying to consume when there's no food left or trying to produce when the plate is already full), the thread waits until the other thread has resolved the inconsistency. This ensures that the shared resource is always in a consistent state.

This example illustrates synchronization by controlling access to shared resources, preventing data corruption and ensuring thread safety.

Java synchronized string

I'd be happy to explain how to use a synchronized string in Java!

In Java, strings are immutable by default, which means that once they're created, their value can't be changed. This is because the String class is final and all its methods are final, making it impossible for any subclass to modify the behavior of these methods.

However, sometimes you may need to use a synchronized string, especially when you have multiple threads accessing a shared string. A synchronized string ensures that only one thread can modify the string at any given time, preventing any potential inconsistencies or data corruption.

Here's an example of how you can create a synchronized string in Java:

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class SynchronizedString {

private String value;

private Lock lock = new ReentrantLock();

public SynchronizedString(String initialValue) {

this.value = initialValue;

}

public void update(String newValue) {

lock.lock();

try {

this.value = newValue;

} finally {

lock.unlock();

}

}

public String getValue() {

return this.value;

}

}

In the above code:

We define a SynchronizedString class that has a private value string and a ReentrantLock. In the constructor, we initialize the value with the given initial value. The update method updates the value of the synchronized string. It locks the lock before updating the value, ensuring that only one thread can modify it at any time. The getValue method returns the current value of the synchronized string.

Here's how you could use this class:

public class Main {

public static void main(String[] args) throws InterruptedException {

SynchronizedString syncStr = new SynchronizedString("Initial Value");

// Create 5 threads that update the synchronized string

for (int i = 0; i < 5; i++) {

Thread thread = new Thread(() -> {

try {

Thread.sleep(100);

syncStr.update("Updated value from thread " + i);

System.out.println("Thread " + i + " updated the string.");

} catch (InterruptedException e) {

e.printStackTrace();

}

});

thread.start();

}

// Wait for all threads to finish

Thread.sleep(500);

System.out.println("Final value of the synchronized string: " + syncStr.getValue());

}

}

In this example:

We create a SynchronizedString object with an initial value. 5 threads update the synchronized string, each with its own unique value. The update method ensures that only one thread can modify the string at any given time. After all threads finish, we print out the final value of the synchronized string.

This example demonstrates how you can use a synchronized string to ensure thread safety when modifying shared strings in Java.