I wrote a simple consumer-producer problem with a blocking queue that has multiple producers and multiple consumers take and putting integers on the queue. However, when I tried to testing it, the results aren't as desired such as the size of the queue is not correct. I don't think the consumer and producer size are syncing together. Moreover, I put a 2 second sleep on both producer and consumer but when testing, every two seconds it prints out the results of 2 producers and 2 consumers. Does anyone know what I am doing wrong? Maybe I am starting the threads wrong? I commented out another way I did it but the results were still wrong.
Results:
run: Producing 425 Thread-0 size left 0 Consuming 890 Thread-3 size left 0 Consuming 425 Thread-2 size left 0 Producing 890 Thread-1 size left 0 Consuming 192 Thread-2 size left 0 Consuming 155 Thread-3 size left 0 Producing 155 Thread-1 size left 0 Producing 192 Thread-0 size left 0 Consuming 141 Thread-2 size left 1 Producing 141 Thread-0 size left 0 Producing 919 Thread-1 size left 0 Consuming 919 Thread-3 size left 0 Producing 361 Thread-1 size left 0 Producing 518 Thread-0 size left 0 Consuming 518 Thread-3 size left 0 Consuming 361 Thread-2 size left 0 Producing 350 Thread-0 size left 1 Consuming 350 Thread-3 size left 0 Consuming 767 Thread-2 size left 0 Producing 767 Thread-1 size left 0 Producer
import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import java.util.logging.Logger; public class Producer implements Runnable { BlockingQueue<Integer> items = new LinkedBlockingQueue<>(); public Producer(BlockingQueue<Integer> q) { this.items = q; } private int generateRandomNumber(int start, int end) { Random rand = new Random(); int number = start + rand.nextInt(end - start + 1); return number; } public void run() { for (int i = 0; i < 5; i++) { int rand = generateRandomNumber(100, 1000); try { items.put(rand); System.out.println("Producing " + rand + " " + Thread.currentThread().getName() + " size left " + items.size()); Thread.sleep(3000); } catch (InterruptedException ex) { Logger.getLogger(ProducerConsumer.class.getName()).log(Level.SEVERE, null, ex); } } } } Consumer
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import java.util.logging.Logger; public class Consumer implements Runnable { BlockingQueue<Integer> items = new LinkedBlockingQueue<>(); public Consumer(BlockingQueue<Integer> q) { this.items = q; } public void run() { while (true) { try { System.out.println("Consuming " + items.take() + " " + Thread.currentThread().getName() + " size left " + items.size()); Thread.sleep(3000); } catch (InterruptedException ex) { Logger.getLogger(ProducerConsumer.class.getName()).log(Level.SEVERE, null, ex); } } } } Test
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class ProducerConsumer { public static void main(String args[]) { BlockingQueue<Integer> items = new LinkedBlockingQueue<>(); Producer producer = new Producer(items); Consumer consumer = new Consumer(items); Thread t1 = new Thread(producer); Thread t2 = new Thread(producer); Thread t3 = new Thread(consumer); Thread t4 = new Thread(consumer); /* Thread t1 = new Thread(new Producer()); Thread t2 = new Thread(new Producer()); Thread t3 = new Thread(new Consumer()); Thread t4 = new Thread(new Consumer()); */ t1.start(); t2.start(); t3.start(); t4.start(); } } UPDATE: I tried to implement the reentrant lock but my program stops at the lock line. Any help? Consumer
import java.util.concurrent.locks.ReentrantReadWriteLock; public class Consumer implements Runnable { //private BlockingQueue<Integer> items = new LinkedBlockingQueue<>(); private MyBlockingQ items; public Consumer(MyBlockingQ q) { this.items = q; } public void run() { while (true) { items.remove(); //Thread.sleep(1000); } } } Producer
import java.util.Random; public class Producer implements Runnable { private MyBlockingQ items; public Producer(MyBlockingQ q) { this.items = q; } private int generateRandomNumber(int start, int end) { Random rand = new Random(); int number = start + rand.nextInt(end - start + 1); return number; } public void run() { for (int i = 0; i < 5; i++) { int rand = generateRandomNumber(100, 1000); items.add(rand); } } } MyBlockingQ (shared resouce)
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Level; import java.util.logging.Logger; public class MyBlockingQ { private BlockingQueue<Integer> items = new LinkedBlockingQueue<>(); private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); public MyBlockingQ() { } public void add(Integer i) { lock.writeLock().lock(); try { items.put(i); System.out.println("Producing " + i + " " + Thread.currentThread().getName() + " size left " + items.size()); } catch (InterruptedException ex) { Logger.getLogger(ProducerConsumer.class.getName()).log(Level.SEVERE, null, ex); } finally { lock.writeLock().unlock(); } } public void remove() { lock.writeLock().lock(); try { int taken = items.take(); System.out.println("Consuming " + taken + " " + Thread.currentThread().getName() + " size left " + items.size()); } catch (InterruptedException ex) { Logger.getLogger(ProducerConsumer.class.getName()).log(Level.SEVERE, null, ex); } finally { lock.writeLock().unlock(); } } } Test
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class ProducerConsumer { public static void main(String args[]) { MyBlockingQ items = new MyBlockingQ(); System.out.println("starting"); Thread t1 = new Thread(new Producer(items)); Thread t2 = new Thread(new Producer(items)); Thread t3 = new Thread(new Consumer(items)); Thread t4 = new Thread(new Consumer(items)); t1.start(); t2.start(); t3.start(); t4.start(); } }