I have written my own implementation of producer consumer problem. But my thread is waiting very long and even with notify. I don't get what is happening.
MainClass.java
public class MainClass {
public static void main(String[] args) throws InterruptedException {
final Thread produce = new Thread(new Runnable() {
@Override
public void run() {
synchronized (Shop.LL) {
if (null != Shop.LL && Shop.LL.size() == 0) {
try {
Producer.produce();
Shop.LL.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
notify();
}}}});
final Thread consume = new Thread(new Runnable() {
@Override
public void run() {
synchronized (Shop.LL) {
System.out.println("Entering consumer");
try {
Consumer.buy();
Shop.LL.wait();
} catch (InterruptedException e) {e.printStackTrace();}
notify();
}}});
produce.start();
consume.start();
produce.join();
consume.join();
}}
Producer.java
public class Producer {
private static String[] fruits = { "apple", "orange", "pineapple", "banana", "cherry", "kiwi" };
protected static synchronized void produce() {
if (Shop.LL.size() == 0) {
System.out.println("Producer selling the .....");
do {
System.out.println(fruits[Shop.i]);
Shop.LL.add(fruits[Shop.i]);
Shop.i++;
} while (Shop.LL.size() <= 1);
}}}
Consumer.java
public class Consumer {
protected static synchronized void buy() {
int i = 0;
if (Shop.LL.size() > 0) {
System.out.println("Cosumer buying the .....");
while (i < 2) {
System.out.println(Shop.LL.get(i));
i++;
}}
Shop.LL.clear();
}}
Shop.java
import java.util.LinkedList;
import java.util.List;
public class Shop {
protected static List<String> LL = new LinkedList<String>();
protected static int i = 0;
}
OUTPUT:
Entering producer
Producer selling the ..... apple orange
Entering consumer
Cosumer buying the ..... apple orange
Here after this both threads are waiting indefinitely and don't know why. But what is the cause?
Thread Dump
8976:
2023-03-24 13:43:31
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.191-b12 mixed mode):
"Thread-1" #11 prio=5 os_prio=0 tid=0x000000001869b000 nid=0x2ca8 in Object.wait() [0x0000000018fae000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5f4ee28> (a java.util.LinkedList)
at java.lang.Object.wait(Unknown Source)
at com.consumer.producer.MainClass$2.run(MainClass.java:58)
- locked <0x00000000d5f4ee28> (a java.util.LinkedList)
at java.lang.Thread.run(Unknown Source)
"Thread-0" #10 prio=5 os_prio=0 tid=0x0000000018694000 nid=0x1328 in Object.wait() [0x0000000018eaf000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5f4ee28> (a java.util.LinkedList)
at java.lang.Object.wait(Unknown Source)
at com.consumer.producer.MainClass$1.run(MainClass.java:25)
- locked <0x00000000d5f4ee28> (a java.util.LinkedList)
at java.lang.Thread.run(Unknown Source)
"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00000000185b8000 nid=0x7f0 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C1 CompilerThread2" #8 daemon prio=9 os_prio=2 tid=0x00000000185b2800 nid=0x11f8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread1" #7 daemon prio=9 os_prio=2 tid=0x0000000016eac000 nid=0x21c8 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"C2 CompilerThread0" #6 daemon prio=9 os_prio=2 tid=0x0000000016e4d800 nid=0x30d0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Attach Listener" #5 daemon prio=5 os_prio=2 tid=0x0000000016e4b800 nid=0x2de0 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" #4 daemon prio=9 os_prio=2 tid=0x0000000016e4a000 nid=0xe38 runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
"Finalizer" #3 daemon prio=8 os_prio=1 tid=0x000000000230b800 nid=0x2688 in Object.wait() [0x00000000181ae000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5e08ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
- locked <0x00000000d5e08ed0> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(Unknown Source)
at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)
"Reference Handler" #2 daemon prio=10 os_prio=2 tid=0x0000000016e19000 nid=0x2b4c in Object.wait() [0x00000000180ae000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5e06bf8> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Unknown Source)
at java.lang.ref.Reference.tryHandlePending(Unknown Source)
- locked <0x00000000d5e06bf8> (a java.lang.ref.Reference$Lock)
at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
"main" #1 prio=5 os_prio=0 tid=0x00000000020be800 nid=0x1908 in Object.wait() [0x000000000220f000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x00000000d5e869f0> (a java.lang.Thread)
at java.lang.Thread.join(Unknown Source)
- locked <0x00000000d5e869f0> (a java.lang.Thread)
at java.lang.Thread.join(Unknown Source)
at com.consumer.producer.MainClass.main(MainClass.java:79)
"VM Thread" os_prio=2 tid=0x0000000016e17800 nid=0x3af8 runnable
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x0000000002228000 nid=0x2e60 runnable
"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x0000000002229800 nid=0x16c4 runnable
"GC task thread#2 (ParallelGC)" os_prio=0 tid=0x000000000222b000 nid=0xe9c runnable
"GC task thread#3 (ParallelGC)" os_prio=0 tid=0x000000000222d800 nid=0x22e4 runnable
"VM Periodic Task Thread" os_prio=2 tid=0x00000000185ba000 nid=0x21f0 waiting on condition
JNI global references: 4
I have modified OP code and tried to keep everything same.
Solution 1: Single producer and single consumer thread
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
public class ClientClass {
// moved items from the producer class, just to use its size in consumer class, but change does not have any impact on the issue
private static final String[] fruits = {"apple", "orange", "pineapple", "banana", "cherry", "kiwi"};
// respective trackers to check the conditions
protected static volatile AtomicInteger fruitProducerTracker = new AtomicInteger();
protected static volatile AtomicInteger fruitConsumerTracker = new AtomicInteger();
public static void main(String[] args) throws InterruptedException {
final Thread produce = new Thread(() -> {
synchronized (Shop.LL) {
// wait before producing
if (Shop.LL.size() != 0) {
try {
Shop.LL.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
try {
Producer.produce();
} catch (InterruptedException e) {
e.printStackTrace();
}
Shop.LL.notifyAll();
}
});
final Thread consume = new Thread(() -> {
synchronized (Shop.LL) {
System.out.println("Entering consumer");
if (Shop.LL.size() == 0) {
try {
Shop.LL.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Consumer.buy();
Shop.LL.notifyAll();
}
});
consume.start();
produce.start();
consume.join();
produce.join();
}
static class Producer {
protected static synchronized void produce() throws InterruptedException {
if (Shop.LL.size() == 0) {
// To publish all the items, adding all items from the same thread
for (int j = 0; j < fruits.length; j++) {
final String fruit = fruits[fruitProducerTracker.getAndIncrement()];
Shop.LL.add(fruit);
System.out.println(Thread.currentThread().getName() + " : Producer selling the ....." + fruit);
}
}
}
}
static class Consumer {
protected static synchronized void buy() {
// To consume all items need to use while, if we use if condition similar to OP, then it will consume only 1 item.
while (fruitConsumerTracker.get() < fruits.length) {
final String item = Shop.LL.remove(0);
fruitConsumerTracker.incrementAndGet();
System.out.println(Thread.currentThread().getName() + " : Consumer buying the ....." + item);
}
}
}
static class Shop {
static final List<String> LL = new LinkedList<String>();
}
}
/*
Entering consumer
Thread-0 : Producer selling the .....apple
Thread-0 : Producer selling the .....orange
Thread-0 : Producer selling the .....pineapple
Thread-0 : Producer selling the .....banana
Thread-0 : Producer selling the .....cherry
Thread-0 : Producer selling the .....kiwi
Thread-1 : Consumer buying the .....apple
Thread-1 : Consumer buying the .....orange
Thread-1 : Consumer buying the .....pineapple
Thread-1 : Consumer buying the .....banana
Thread-1 : Consumer buying the .....cherry
Thread-1 : Consumer buying the .....kiwi
*/