Producer consumer problem in Java using Synchronised block
The producer-consumer problem in Java, commonly known as the bounded-buffer problem, is a well-known multi-process synchronization challenge where we attempt to synchronize many processes.
Two processes are involved in the producer-consumer problem: the producer and the consumer. These processes share a single, fixed-size buffer that serves as a queue. Producing data (items) and inserting them into the buffer are the producers' duties. The consumer does data consumption by removing it from the queue.
The difficulty or complications of the producer-consumer problem:
- When the buffer is filled, the producer shouldn't output more data. In this situation, the producer should wait until the consumer has finished using the data and some buffer space has been freed.
- In this instance, the producer should wait until the consumer receives data and some buffer space has been cleared.
- Whenever the buffer is full, the consumer could consume data. Instead, the consumer can only do so when the buffer is not full (i.e., cannot remove data from the queue).
- The producer and consumers shouldn't both have simultaneous access to the memory buffer.
Example
Consider a factory that manufactures products and stores them in its storage; the factory will only produce products when it has room in its storage to do so. If the storage is filled, the factory will wait until the product has been consumed before resuming production. Comparably, if the storage is empty, the consumers cannot consume an item. Instead, the consumer must wait until there is another item in the store to consume.

Solution for producer-consumer problem
We'll implement two main techniques: acquire () and release ().
If a permit is accessible, the acquire() procedure immediately obtains it from the semaphore and returns. Then it subtracts 1 from the total number of permits available.
Suppose no permit is accessible for the current thread. In that case, it enters an inactive state and remains there until either another thread calls the release() procedure, or the other thread terminates the existing thread. When a thread is terminated, the InterruptedException exception will be thrown.
The release() method eliminates a permit, returns it to the semaphore, and raises the total number of available permits by 1. Each thread attempting to obtain a permit is given permission to do so by the semaphore.
The classes in the problem are:
Producer: To build the items that are creating the thing and add them to the buffer.
Consumers: Create objects to take stuff out of the buffer or consumers.
Queue: The queue we wish to synchronise is this one.
Producer, Consumer, and Queue are all created in this class called ThreadSynchronise.
Filename:Synchronisation.java
//Java Program for Producer consumer using Synchronisation
import java.util.concurrent.Semaphore;
class Queue {
int items;
static Semaphore Cons = new Semaphore(0);
static Semaphore Prods = new Semaphore(1);
// in item is from the buffer
void gets()
{
try {
Cons.acquire();
}
catch (InterruptedException e) {
System.out.println("An InterruptedException caught");
}
// the item is consumed by the consumer
System.out.println("The Consumer consumed item is: " + items);
// After the consumer notifies to producer
Prods.release();
}
// to put an item in the buffer
void put(int items)
{
try {
Prods.acquire();
}
catch (InterruptedException e) {
System.out.println("An InterruptedException caught");
}
// the producer is producing an item
this.items = items;
System.out.println("The Producer produced item is: " + items);
// after the relase of producer it is verified by consumer
Cons.release();
}
}
//A class for Producer
class Producers implements Runnable {
Queue q1;
Producers(Queue q1)
{
this.q1 = q1;
new Thread(this, "Producers").start();
}
public void run()
{
for (int i = 0; i < 5; i++)
q1.put(i);
}
}
// The Consumers Class
class Consumers implements Runnable {
Queue q1;
Consumers(Queue q1)
{
this.q1 = q1;
new Thread(this, "Consumers").start();
}
public void run()
{
for (int i = 0; i < 5; i++)
// the items are retrieved by the consumer
q1.gets();
}
}
// Main section of the program
class Synchronisation{
public static void main(String args[])
{
// A buffer que is created for storing the values
Queue q1 = new Queue();
// The initial is the consumer thread
new Consumers(q1);
//The initial Producer thread
new Producers(q1);
}
}
Output
The Producer produced item is: 0
The Consumer consumed item is: 0
The Producer produced item is: 1
The Consumer consumed item is: 1
The Producer produced item is: 2
The Consumer consumed item is: 2
The Producer produced item is: 3
The Consumer consumed item is: 3
The Producer produced item is: 4
The Consumer consumed item is: 4