What is a real time example of synchronization in Java?
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.
What is synchronized vs concurrent in Java?
I'm happy to help!
In Java, both "synchronized" and "concurrent" refer to the way multiple threads interact with each other when accessing shared resources. However, they differ in their approach and implications.
Synchronized:
"Synchronized" is a keyword in Java that ensures only one thread can execute a particular block of code at a time. It's used to protect access to shared resources, such as variables or objects, from being modified by multiple threads simultaneously.
When you mark a method or block of code as synchronized, it means that any thread trying to enter that section will need to acquire a lock (also known as a mutex) before proceeding. If the lock is already held by another thread, the current thread will wait until the lock is released before entering.
Synchronization is achieved through the use of a shared object called a "monitor" or "lock." A monitor is essentially a Java object that has methods to acquire and release locks.
Here's an example of a synchronized method in Java:
public class SynchronizedExample {
public static synchronized void doSomething() {
// code here will be executed by only one thread at a time
}
}
Concurrent:
"Concurrent," on the other hand, refers to the ability of multiple threads to execute simultaneously without interfering with each other. In Java, concurrency is achieved through the use of high-level abstractions, such as Executor Framework, Fork/Join framework, or low-level APIs like ThreadLocalRandom.
Concurrency is about managing and coordinating the interactions between multiple threads that share common resources. It's about ensuring that each thread gets a fair chance to execute and make progress without conflicts arising from shared resource access.
Java provides various concurrency utilities, such as:
ExecutorService: Manages a pool of worker threads. ForkJoinPool: A pool of worker threads that can be used for parallel computations. ThreadLocalRandom: Provides thread-local random number generation.Here's an example of using the Executor Framework to execute concurrent tasks:
public class ConcurrencyExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(5);
List<Callable> tasks = new ArrayList<>();
for (int i = 0; i < 10; i++) {
tasks.add(new Callable() {
@Override
public String call() throws Exception {
// do some work here...
return "Task completed: " + Thread.currentThread().getName();
}
});
}
List<Future> futures = executor.invokeAll(tasks);
for (Future future : futures) {
try {
System.out.println(future.get());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
In summary, synchronization in Java ensures that only one thread can execute a particular block of code at a time, while concurrency enables multiple threads to run simultaneously without interfering with each other. Both are essential for building robust and efficient multithreaded applications.
Hope this answers your question!