Bounded buffer problem in Java
The Bounded buffer Problem can also be called a Producer consumer problem. The problem covers two processes—the producer and the consumer—that share a single, fixed-size buffer that serves as a queue.
- Data generation, buffering, and restarting are all tasks performed by the producer.
- The consumer simultaneously consumes the data (i.e., removed from the buffer), one piece at a time.
The producer must either sleep or destroy data when the buffer is full. When a consumer later takes an item out of the buffer, the producer is notified, and the buffer is once more filled. In the same way, if the consumer detects that the buffer is empty, it can nod off. The consumer is awakened when the producer inserts data into the buffer to find significance.
A poor response can leave both processes in a sleeping state, unable to move on.

Approach
- A LinkedList list is used to store the queue of open jobs.
- A variable capacity to determine whether the waiting list is full or not
- a way to regulate the addition to and removal from this list so that we don't add to it if it is already full or remove it if it is already empty.
Filename: Threadex.java
// Java program to implement the solution of the producer
// consumer problem.
import java.util.LinkedList;
public class Threadex {
public static void main(String[] args)
throws InterruptedException
{
// Object of a class that has both produce()
// and consume() methods
final PC pc = new PC();
// Create a producer thread
Thread t1 = new Thread(new Runnable() {
@Override
public void run()
{
try {
pc.produce();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Create a consumer thread
Thread t2 = new Thread(new Runnable() {
@Override
public void run()
{
try {
pc.consume();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// Start both threads
t1.start();
t2.start();
// t1 finishes before t2
t1.join();
t2.join();
}
// This class has a list, producer (adds items to list
// and consumer (removes items).
public static class PC {
// Create a list shared by the producer and consumer
// Size of the list is 2.
LinkedList<Integer> list = new LinkedList<>();
int capacity = 2;
// Function called by producer thread
public void produce() throws InterruptedException
{
int value = 0;
while (true) {
synchronized (this)
{
// producer thread waits while the list
// is full
while (list.size() == capacity)
wait();
System.out.println("Producer produced-" + value);
// to insert the jobs in the list
list.add(value++);
// notifies the consumer thread that
// now it can start consuming
notify();
// makes the working of the program easier
// to understand
Thread.sleep(1000);
}
}
}
// Function called by the consumer thread
public void consume() throws InterruptedException
{
while (true) {
synchronized (this)
{
// consumer thread waits while the list
// is empty
while (list.size() == 0)
wait();
// to retrieve the first job in the list
int val = list.removeFirst();
System.out.println("Consumer consumed-“,+ val);
// Wake up producer thread
notify();
// and sleep
Thread.sleep(1000);
}
}
}
}
}
Output
Producer produced-0
Producer produced-1
The Consumer consumed-0
The Consumer consumed-1
Producer produced-2
Important points
- To ensure that the producer does not produce unless the list is full, a linked list of tasks and a capability of the list are introduced to the PC class (a class that includes both produce and consumption methods).
- The initial value for the Producer class is 0.
- We also have an endless outer loop that we can use to add values to the list. Only one producer or consumer thread may be active at once because of the synchronised block inside this loop.
- The production threads give up the fundamental lock on the PC and enter the waiting state before putting the jobs to the list in a loop that verifies whether the job list is full.
- The control moves to the loop above if the list is empty, where it adds a value to the list.
- We use an infinite loop in the Consumer class to pull a value from the list.
- An inner loop that determines whether the list is empty is also present.
- If empty, we force the consumer thread to release the PC lock and transfer control to the producer thread, creating additional tasks.
- If the list contains any items, we loop back around and remove one at a time.
- We utilize notification after every statement in both approaches. The explanation is straightforward: if something is on the list, it can be eaten by a consumer thread or produced by a producer thread, even if you've consumed something.
- By adding a sleep() after both procedures, you can see what is happening in the program by having the output run step-by-step rather than all at once.