I'm currently developing a programme using multiple producer threads, and one consumer thread. I am wondering if there is an easy way to reference exactly which Producer Thread the Consumer Thread has consumed from.
Here's an example of my output so far:
ConsumerThread consumed: 12 bytes
I would like it to be, for example:
ConsumerThread consumed: 12 bytes from ThreadA
ConsumerThread consumed: 62 bytes from ThreadB
Here is my Consumer Code, called CPU in this case:
class CPU implements Runnable {
private final Vector processingQueue;
private final int SIZE;
public CPU (Vector processingQueue, int size) {
this.processingQueue = processingQueue;
this.SIZE = size;
}
public void run() {
while (true) {
try {
System.out.println("CPU processing: " + consume() + " bytes");
Thread.sleep(50);
} catch (InterruptedException ex) {
Logger.getLogger(CPU.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
private int consume() throws InterruptedException {
//wait if queue is empty
while (processingQueue.isEmpty()) {
synchronized (processingQueue) {
System.out.println("Queue is empty " + Thread.currentThread().getName()
+ " is waiting , size: " + processingQueue.size());
processingQueue.wait();
}
}
//Otherwise consume element and notify waiting producer
synchronized (processingQueue) {
processingQueue.notifyAll();
return (Integer) processingQueue.remove(0);
}
}
}
Here's an example of one of my producers, called OperatingSystem:
public class OperatingSystem extends Thread {
private final Vector processingQueue;
private final int SIZE;
public OperatingSystem (Vector processingQueue, int size) {
this.processingQueue = processingQueue;
this.SIZE = size;
}
private void produce(int i) throws InterruptedException {
// suspend producing if queue is full
while (processingQueue.size() == SIZE) {
synchronized (processingQueue) {
System.out.println("Queue is full " + Thread.currentThread().getName()
+ " is waiting , size: " + processingQueue.size());
processingQueue.wait();
}
}
// producing element and notify consumers
synchronized (processingQueue) {
processingQueue.add(i);
processingQueue.notifyAll();
}
}
public void run() {
//OperatingSystem using 300bytes
for (int i = 0; i <= 300; i++) {
System.out.println("Operating System producing: " + i + " bytes");
try {
produce(i);
} catch (InterruptedException ex) {
Logger.getLogger(OperatingSystem.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}//OperatingSystem
Any help would be great, thanks!
Each producer would have to attach its name / identifier to the queue with the actual information (in your case, an int).
class Data {
int data;
String source;
}
And, instead of writing and reading integers from the queue, use Data instances.
You can use setName(String name) from Thread class to identify the producer threads accordingly.
Related
My producer-consumer problem runs perfectly for 1 producer and 1 consumer. It fails to run for 2 producer and 2 consumer. It is reaching some unknown deadlock state. I'm not able to debug. Can anyone please help me with it?
Constraint: One Producer has to produce upto 64 items. And consumer runs until it clears all produced items.
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
class Producer implements Runnable {
private static int count = 1;
private Random rg = new Random();
private BlockingQueue<Object> queue = null;
private static int pc = 0;
static int maxPc = 0;
public Producer(BlockingQueue<Object> queue) {
this.queue = queue;
}
#Override
public void run() {
synchronized (queue) {
while(pc <= maxPc) {
try {
produce(pc++);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public void produce(int pc) throws InterruptedException {
synchronized(queue) {
while(queue.size() == 8) {
System.out.println(Thread.currentThread().getName() + " : Buffer full: waiting for consumer");
queue.wait();
}
}
synchronized(queue) {
System.out.println("Producer: " + Thread.currentThread().getName() + " adding item "+ pc + " to the queue");
queue.add(pc);
//Thread.sleep(1);
queue.notifyAll();
}
}
}
class Consumer implements Runnable {
private static int consumeCount = 0;
private BlockingQueue<Object> queue = null;
private Random rg = new Random();
public Consumer(BlockingQueue<Object> queue) {
this.queue = queue;
}
#Override
public void run() {
while(true) {
try {
consume();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void consume() throws InterruptedException {
synchronized(queue) {
while(queue.isEmpty()) {
System.out.println(Thread.currentThread().getName() + ": Buffer empty: waiting for producer");
queue.wait();
}
}
synchronized(queue) {
//Thread.sleep(1);
System.out.println("Consumer: "+ Thread.currentThread().getName()+" removing item " + queue.take() + " from the queue");
consumeCount++;
queue.notifyAll();
if(consumeCount == ParallelProcess.maxCC + 1)
System.exit(0);
}
}
}
public class ParallelProcess {
static int maxCC = 0;
int numProducer;
int numConsumer;
private Thread[] cThreads;
private Thread[] pThreads;
private BlockingQueue<Object> queue = null;
public ParallelProcess(int numProducer, int numConsumer, int queueSize) {
this.numProducer = numProducer;
this.numConsumer = numConsumer;
this.queue = new ArrayBlockingQueue<Object>(queueSize);
// create consumer thread objects
cThreads = new Thread[numConsumer];
for (int i = 0; i < numConsumer; i++) {
cThreads[i] = new Thread(new Consumer(queue));
}
// create producer thread objects
pThreads = new Thread[numProducer];
for (int i = 0; i < numProducer; i++) {
pThreads[i] = new Thread(new Producer(queue));
}
}
public void execute() {
// start consumer threads
for (Thread t : cThreads) {
t.start();
}
// start producer threads
for (Thread t : pThreads) {
//System.out.println("tc");
t.start();
}
}
public static void main(String[] args) {
// provide number of producers, number of consumers and the
// max-queue-length
Scanner sc = new Scanner(System.in);
System.out.println("Enter no. of producer and conumer");
int n = sc.nextInt();
ParallelProcess process = new ParallelProcess(n, n, 8);
maxCC = n*64;
Producer.maxPc = maxCC;
process.execute();
// (new Thread()).start();
System.out.println("Thread: " + Thread.currentThread().getName() + " `enter code here`FINISHED");
}
}
First, you should merge synchronized block of the wait and queue.add(pc) to make it automatic, otherwise it might cause some inconstency.
Secondly, you should call queue.notify before wait, otherwise both producer and consumer might be blocked in wait state.
produce method:
public void produce(int pc) throws InterruptedException {
synchronized(queue) {
while(queue.size() == 8) {
System.out.println(Thread.currentThread().getName() + " : Buffer full: waiting for consumer");
queue.notifyAll();
queue.wait();
}
System.out.println("Producer: " + Thread.currentThread().getName() + " adding item "+ pc + " to the queue");
queue.add(pc);
//Thread.sleep(1);
queue.notifyAll();
}
}
consume method:
public void consume() throws InterruptedException {
synchronized(queue) {
while(queue.isEmpty()) {
System.out.println(Thread.currentThread().getName() + ": Buffer empty: waiting for producer");
queue.notifyAll();
queue.wait();
}
System.out.println("Consumer: "+ Thread.currentThread().getName()+" removing item " + queue.take() + " from the queue");
consumeCount++;
if(consumeCount == ParallelProcess.maxCC + 1)
System.exit(0);
}
}
the code at the bottom (1) was just for exercising but makes me curious why always the same Thread and only this Thread is able to receive the resource made by the producer. When I update the producer part with a Thread.sleep in my code like (2) all Threads get the resource randomly (I think). But why? Does the Sheduler works with LIFO? Or whats the "problem" here?
1
public class ProducerConsumer {
private static int resource = 0;
private static AtomicInteger id = new AtomicInteger();
public static void main(String... args) throws InterruptedException {
final Object monitor = new Object();
Runnable producer = () -> {
try {
while (!Thread.interrupted()) {
// produce number
println("producing ...");
int number = (int) (Math.random() * 1000) + 1;
Thread.sleep(number);
println("produced " + number);
// send number
synchronized (monitor) {
resource = number;
println("notified");
monitor.notifyAll();
}
}
} catch (InterruptedException e) {
println("interrupted");
}
};
Runnable consumer = () -> {
final int innerId = id.getAndIncrement();
try {
while (!Thread.interrupted()) {
// receive number
int number;
synchronized (monitor) {
while (resource == 0) {
println(innerId + " waiting ...");
monitor.wait();
println(innerId + " woke up ...");
}
number = resource;
resource = 0;
}
// consume number
println("consumed " + number);
}
} catch (Exception e) {
println("interrupted");
}
};
new Thread(producer).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
new Thread(consumer).start();
Thread.sleep(10_000);
Thread.currentThread().getThreadGroup().interrupt();
}
}
2
Runnable producer = () -> {
try {
while (!Thread.interrupted()) {
// produce number
println("producing ...");
final int number = (int) (Math.random() * 1000) + 1;
Thread.sleep(number);
println("produced " + number);
synchronized (monitor) {
setResource(number);
println("notified");
Thread.sleep(100);
monitor.notifyAll();
}
}
} catch (InterruptedException e) {
println("interrupted");
}
};
It is pseudo-random.
From the notifyAll doc:
The awakened threads will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened threads enjoy no reliable privilege or disadvantage in being the next thread to lock this object.
The implementation seems to fairly reliable (not random) in your case, but like the documentation says, it is not 100% reliable.
I have a queue of running threads and would like to expose some of its data while it is executed, to monitor the process.
ThreadPoolExecutor provides access to its queue and I can iterate through these objects to call my overridden toString() method, but these are only threads that are waiting for execution.
Is there a way to access threads that are currently running to call my method? Or maybe there's a better approach for this task in general?
To clarify a bit more about the purpose, here's some code of general idea:
public class GetDataTask implements Runnable {
private String pageNumber;
private int dataBlocksParsed;
private String source;
private String dataType;
public GetDataTask(String source, String dataType) {
this.source = source;
this.dataType = dataType;
}
#Override
public void run() {
//do stuff that affects pageNumber and dataBlocksParsed
}
#Override
public String toString() {
return "GetDataTask{" +
"source=" + source +
", dataType=" + dataType +
", pageNumber=" + pageNumber +
", dataBlocksParsed=" + dataBlocksParsed +
'}';
}
}
and a class holding the executor:
public class DataParseManager {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<>(300));
public void addParseDataTask(String source, String dataType) {
executor.execute(new GetDataTask(source, dataType));
}
// here's the method that I need
public String getInfo() {
StringBuilder info = new StringBuilder();
//and here's the method that I'm missing - executor.getActiveThreads()
for (Runnable r : executor.getActiveThreads()) {
info.append(((GetDataTask) r).toString()).append('\n');
}
return info.append(executor.toString()).toString();
}
}
How about wrap Runnable like this.
static class MonitorRunnable implements Runnable {
static final List<Runnable> activeTasks = Collections.synchronizedList(new ArrayList<>());
private final Runnable runnable;
public MonitorRunnable(Runnable runnable) {
this.runnable = runnable;
}
#Override
public void run() {
activeTasks.add(runnable);
runnable.run();
activeTasks.remove(runnable);
}
}
and
public class DataParseManager {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<>(300));
public void addParseDataTask(String source, String dataType) {
executor.execute(new MonitorRunnable(new GetDataTask(source, dataType)));
}
// here's the method that I need
public String getInfo() {
StringBuilder info = new StringBuilder();
//and here's the method that I'm missing - executor.getActiveThreads()
synchronized (MonitorRunnable.activeTasks) {
for (Runnable r : MonitorRunnable.activeTasks) {
info.append(((GetDataTask) r).toString()).append('\n');
}
}
return info.append(executor.toString()).toString();
}
}
Whenever you add a thread to the queue, also add it to a second data structure, say a HashSet. Then, if you need to access a running thread, you could check the ExecutorService's queue to find the Threads that are still awaiting execution: every thread in your HashSet that is not still in the ExecutorService's queue is currently running.
Like I wrote in comment. I'd do an active update on a shared statistics object approach:
I'd change the Task like this:
public class GetDataTask implements Runnable {
private String pageNumber;
private int dataBlocksParsed;
private String source;
private String dataType;
HashMap<GetDataTask,String> statistics
public GetDataTask(String source, String dataType, HashMap<GetDataTask,String> statistics) {
this.source = source;
this.dataType = dataType;
this.statistics = statistics;
}
#Override
public void run() {
// you'll probably want to immediately have stats available:
statistics.put(this, this.toString());
//do stuff that affects pageNumber and dataBlocksParsed
// vv this will probably be inside your "do stuff" loop
statistics.put(this, this.toString());
// loop end
// if you do not want stats of finished tasks, remove "this" here.
}
#Override
public String toString() {
return "GetDataTask{" +
"source=" + source +
", dataType=" + dataType +
", pageNumber=" + pageNumber +
", dataBlocksParsed=" + dataBlocksParsed +
'}';
}
}
and the manager:
public class DataParseManager {
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(100, 100, 20, TimeUnit.SECONDS, new ArrayBlockingQueue<>(300));
private HashMap<GetDataTask,String> stats = new ConcurrentHashMap<GetDataTask,String>();
public void addParseDataTask(String source, String dataType) {
executor.execute(new GetDataTask(source, dataType, stats));
}
// here's the method that I need
public String getInfo() {
StringBuilder info = new StringBuilder();
//and here's the method that I'm missing - executor.getActiveThreads()
// >>> iterate "stats"'s values to build the info string ...
return info.append(executor.toString()).toString();
}
}
UPDATE
You can easily change that approach to pulling the info by iterating the Map's keys (which are the executing tasks) and call toString on them. This is quite similar to saka's approach, though. Maybe you feel more comfortable with his.
Since you have control over the used executor, I would use the ThreadPoolExecutor's beforeExecute and afterExecute methods to keep track of running tasks and use that to create a getActiveTasks method.
import java.util.Set;
import java.util.concurrent.*;
public class ActiveTasksThreadPool extends ThreadPoolExecutor {
private final ConcurrentHashMap<Runnable, Boolean> activeTasks = new ConcurrentHashMap<>();
public ActiveTasksThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
#Override
protected void beforeExecute(Thread t, Runnable r) {
activeTasks.put(r, Boolean.TRUE);
super.beforeExecute(t, r);
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
activeTasks.remove(r);
}
public Set<Runnable> getActiveTasks() {
// the returned set will not throw a ConcurrentModificationException.
return activeTasks.keySet();
}
public static void main(String[] args) {
final int maxTasks = 5;
ActiveTasksThreadPool tp = new ActiveTasksThreadPool(maxTasks, maxTasks, 10, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
try {
System.out.println("Active tasks: " + tp.getActiveTasks());
final CountDownLatch latch = new CountDownLatch(1);
for (int i = 0; i < maxTasks; i ++) {
final int rnumber = i;
tp.execute(new Runnable() {
#Override
public void run() {
try { latch.await(); } catch (Exception e) {
e.printStackTrace();
}
}
#Override
public String toString() {
return "Runnable " + rnumber;
}
});
}
Thread.sleep(100L); // give threads a chance to start
System.out.println("Active tasks: " + tp.getActiveTasks());
latch.countDown();
Thread.sleep(100L); // give threads a chance to finish
System.out.println("Active tasks: " + tp.getActiveTasks());
} catch (Exception e) {
e.printStackTrace();
} finally {
tp.shutdownNow();
}
}
}
You just need to store the references to the running threads somewhere which will be triggered within the ThreadPoolExecutor, adding on top of the other answers, this is an example of a small application which reads Thread states running inside the ThreadPoolExecutor every 1 second until shutdown:
package sample;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
for (int i = 1; i <= 10; i++)
{
Task task = new Task("Task " + i);
executor.execute(task);
}
executor.shutdown();
try {
while (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
System.out.println("Awaiting completion of threads, threads states: " + Task.getThreadsStateCount());
}
} catch (InterruptedException e) {
}
System.out.println("Executor shutdown -> " + executor.isShutdown());
}
}
class Task implements Runnable {
static final List<Thread> activeTasks = Collections.synchronizedList(new ArrayList<>());
static final Random r = new Random();
private String name;
public Task(String name) {
this.name = name;
}
#Override
public void run() {
Thread t = Thread.currentThread();
System.out.println("current thread : " + t.getName() + " group " + t.getThreadGroup() + " state " + t.getState());
activeTasks.add(t);
try {
int tries = 0;
while (tries < 10) {
int randomNum = r.nextInt(10000);
// do some expensive computation
for(int i = 0; i < 4; i++) {
isPrime(r.nextLong());
}
// now sleep
Thread.sleep(randomNum);
tries++;
}
} catch (InterruptedException e) {
}
System.out.println("completed task for thread : " + t.getName() + " group " + t.getThreadGroup() + " state " + t.getState());
}
static boolean isPrime(long n)
{
if (n <= 1)
return false;
if (n <= 3)
return true;
if (n % 2 == 0 || n % 3 == 0)
return false;
for (int i = 5; i * i <= n; i = i + 6)
if (n % i == 0 || n % (i + 2) == 0)
return false;
return true;
}
public static String getThreadsStateCount() {
return "NEW: " + getCountThreadsState(Thread.State.NEW) +
" ,RUNNABLE: " + getCountThreadsState(Thread.State.RUNNABLE) +
" ,WAITING: " + getCountThreadsState(Thread.State.WAITING) +
" ,TIMED_WAITING: " + getCountThreadsState(Thread.State.TIMED_WAITING) +
" ,BLOCKED: " + getCountThreadsState(Thread.State.BLOCKED) +
" ,TERMINATED: " + getCountThreadsState(Thread.State.TERMINATED);
}
public static long getCountThreadsState(Thread.State state) {
return activeTasks.stream().filter(x -> x.getState() == state).count();
}
}
// prints something like:
Awaiting completion of threads, threads states: NEW: 0 ,RUNNABLE: 1
,WAITING: 0 ,TIMED_WAITING: 9 ,BLOCKED: 0 ,TERMINATED: 0
I’m writing a program that implements the Producer Consumer problem in Java using multithreading concepts. Below are few details how I’m supposed to do it:
1) The main thread should create a buffer with capacity specified as a command line argument. The number of producer and consumer threads are also specified as command line arguments. I’m supposed to assign a unique number to each producer and consumer thread. How do I assign a unique number to producer and consumer threads?
2) The producer thread operates in an infinite loop. It produces a data item (a string) with the following format: <producer number>_<data item number>. For example the 1st data item from thread number 1 will be 1_1 and second data item from thread number 3 will be 3_2. How do create data items in such a format?
3) Then the Producer thread writes an entry into the producer log file (< producer number > “Generated” <data item>). Upon writing the log entry, it attempts to insert into the buffer. If insertion is successful, it creates an entry into the log file (<producer number> <data item> “Insertion successful”). How do I write such a code?
Below is the Java code I wrote.
import java.util.*;
import java.util.logging.*;
public class PC2
{
public static void main(String args[])
{
ArrayList<Integer> queue = new ArrayList<Integer>();
int size = Integer.parseInt(args[2]);
Thread[] prod = new Thread[Integer.parseInt(args[0])];
Thread[] cons = new Thread[Integer.parseInt(args[1])];
for(int i=0; i<prod.length; i++)
{
prod[i] = new Thread(new Producer(queue, size));
prod[i].start();
}
for(int i=0; i<cons.length; i++)
{
cons[i] = new Thread(new Consumer(queue, size));
cons[i].start();
}
}
}
class Producer extends Thread
{
private final ArrayList<Integer> queue;
private final int size;
public Producer(ArrayList<Integer> queue, int size)
{
this.queue = queue;
this.size = size;
}
public void run()
{
while(true){
for(int i=0; i<size; i++)
{
System.out.println("Produced: "+i+" by id " +Thread.currentThread().getId());
try
{
produce(i);
Thread.sleep(3000);
}
catch(Exception e)
{
Logger.getLogger(Producer.class.getName()).log(Level.SEVERE, null, e);
}
}}
}
public void produce(int i) throws InterruptedException
{
while(queue.size() == size)
{
synchronized(queue)
{
System.out.println("Queue is full "+Thread.currentThread().getName() +" is waiting, size: "+queue.size());
queue.wait();
}
}
synchronized(queue)
{
queue.add(i);
queue.notifyAll();
}
}
}
class Consumer extends Thread
{
private final ArrayList<Integer> queue;
private final int size;
public Consumer(ArrayList<Integer> queue, int size)
{
this.queue = queue;
this.size = size;
}
public void run()
{
while(true)
{
try
{ System.out.println("Consumed: "+consume());
Thread.sleep(1000);
}
catch(Exception e)
{
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE, null, e);
}
}
}
public int consume() throws InterruptedException
{
while(queue.isEmpty())
{
synchronized(queue)
{
System.out.println("Queue is empty "+Thread.currentThread().getName()+" is waiting, size: "+queue.size());
queue.wait();
}
}
synchronized (queue)
{
queue.notifyAll();
System.out.println("Consumed by id "+Thread.currentThread().getId());
return (Integer) queue.remove(0);
}
}
}
How can I carry out the above steps?
I’m supposed to assign a unique number to each producer and consumer
thread. How do I assign a unique number to producer and consumer
threads?
Add an instance (non-static) variable to the Producer/Consumer classes. When you initialize the new Producer/Consumer Objects, pass in the unique number. You can keep track of what number you're on with an int counter in your main class.
2) The producer thread operates in an infinite loop. It produces a
data item (a string) with the following format: < producer number >_<
data item number > . For example the 1st data item from thread number
1 will be 1_1 and second data item from thread number 3 will be 3_2.
How do create data items in such a format?
Use synchronized methods and/or atomic variables. Look into Java Concurrency.
3) Then the Producer thread writes an entry into the producer log file
(< producer number > “Generated” < data item >). Upon writing the log
entry, it attempts to insert into the buffer. If insertion is
successful, it creates an entry into the log file (< producer number >
< data item > “Insertion successful”). How do I write such a code?
My answer is the same as the previous question: read about Java concurrency. Spend an hour reading about synchronization, locks, and atomic variables and I guarantee you will easily write your program.
For producer consumer problem best solution is BlockingQueue. I was testing a few things so designed same kind of program now modified it as per your need.
See if it helps.
import java.util.concurrent.*;
public class ThreadingExample {
public static void main(String args[]){
BlockingQueue<Message> blockingQueue = new ArrayBlockingQueue<Message>(100);
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new Producer(blockingQueue));
exec.execute(new Consumer(blockingQueue));
}
}
class Message{
private static int count=0;
int messageId;
Message(){
this.messageId=count++;
System.out.print("message Id"+messageId+" Created ");
}
}
class Producer implements Runnable{
private BlockingQueue<Message> blockingQueue;
Producer(BlockingQueue<Message> blockingQueue){
this.blockingQueue=blockingQueue;
}
#Override
public void run(){
while(!Thread.interrupted()){
System.out.print("Producer Started");
try {
blockingQueue.put(new Message());
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Producer Done");
}
}
}
class Consumer implements Runnable{
private BlockingQueue<Message> blockingQueue;
Consumer(BlockingQueue<Message> blockingQueue){
this.blockingQueue=blockingQueue;
}
#Override
public void run(){
while(!Thread.interrupted()){
System.out.print("Concumer Started");
try{
Message message = blockingQueue.take();
System.out.print("message Id"+message.messageId+" Consumed ");
}
catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("Concumer Done");
}
}
}
I tried the following which might work for you, except for the buffer condition on 3, which you can add the part of the code by yourself.
Hope this helps.
public class Message {
private String msg;
public Message(String msg) {
super();
this.msg = msg;
}
public String getMsg(){
return msg;
}
}
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable {
private BlockingQueue<Message> queue;
private boolean run = true;
public Producer(BlockingQueue<Message> queue) {
super();
this.queue = queue;
}
public void setRun(boolean val) {
this.run = val;
}
#Override
public void run() {
int i = 0;
while (run) {
Message msg = new Message(Thread.currentThread().getName() + "_"+ i);
try {
Thread.sleep(i * 100);
queue.put(msg);
System.out.println("Producer: "+Thread.currentThread().getName()+" produced and added to the queue: "+msg.getMsg());
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
if(i==10){
setRun(false);
System.out.println(Thread.currentThread().getName()+" stopped");
}
}
}
}
import java.util.concurrent.BlockingQueue;
public class Consumer implements Runnable{
private BlockingQueue<Message> queue;
private boolean run = true;
public Consumer(BlockingQueue<Message> queue) {
super();
this.queue = queue;
}
public void setRun(boolean val){
this.run = val;
}
#Override
public void run() {
while(run){
try {
Thread.sleep(100);
Message msg = queue.take();
System.out.println("Consumer: "+Thread.currentThread().getName()+" generated/consumed "+msg.getMsg());
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ProducerConsumerMain {
public static void main(String[] args) {
System.out
.println("please enter the number of producer:consumer:size of the queue in order");
Scanner scan = new Scanner(System.in);
Thread[] prodThreads = new Thread[scan.nextInt()];
Thread[] consThreads = new Thread[scan.nextInt()];
BlockingQueue<Message> queue = new ArrayBlockingQueue<Message>(scan.nextInt());
for (int i = 0; i < prodThreads.length; i++) {
prodThreads[i] = new Thread(new Producer(queue), "" + i);
prodThreads[i].start();
}
for (int i = 0; i < consThreads.length; i++) {
consThreads[i] = new Thread(new Consumer(queue), "" + i);
consThreads[i].start();
}
}
}
Please refer the below code. You can change the constant values based on the command line arguments. I have tested the code, its working as per your requirement.
import java.util.LinkedList;
import java.util.Queue;
public class ProducerConsumerProblem {
public static int CAPACITY = 10; // At a time maximum of 10 tasks can be
// produced.
public static int PRODUCERS = 2;
public static int CONSUMERS = 4;
public static void main(String args[]) {
Queue<String> mTasks = new LinkedList<String>();
for (int i = 1; i <= PRODUCERS; i++) {
Thread producer = new Thread(new Producer(mTasks));
producer.setName("Producer " + i);
producer.start();
}
for (int i = 1; i <= CONSUMERS; i++) {
Thread consumer = new Thread(new Consumer(mTasks));
consumer.setName("Consumer " + i);
consumer.start();
}
}
}
class Producer implements Runnable {
Queue<String> mSharedTasks;
int taskCount = 1;
public Producer(Queue<String> mSharedTasks) {
super();
this.mSharedTasks = mSharedTasks;
}
#Override
public void run() {
while (true) {
synchronized (mSharedTasks) {
try {
if (mSharedTasks.size() == ProducerConsumerProblem.CAPACITY) {
System.out.println("Producer Waiting!!");
mSharedTasks.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (mSharedTasks.size() != ProducerConsumerProblem.CAPACITY) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
String produceHere = Thread.currentThread().getName()
+ "_Item number_" + taskCount++;
synchronized (mSharedTasks) {
mSharedTasks.add(produceHere);
System.out.println(produceHere);
if (mSharedTasks.size() == 1) {
mSharedTasks.notifyAll(); // Informs consumer that there
// is something to consume.
}
}
}
}
}
}
class Consumer implements Runnable {
Queue<String> mSharedTasks;
public Consumer(Queue<String> mSharedTasks) {
super();
this.mSharedTasks = mSharedTasks;
}
#Override
public void run() {
while (true) {
synchronized (mSharedTasks) {
if (mSharedTasks.isEmpty()) { // Checks whether there is no task
// to consume.
try {
mSharedTasks.wait(); // Waits for producer to produce!
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
while (!mSharedTasks.isEmpty()) { // Consumes till task list is
// empty
try {
// Consumer consumes late hence producer has to wait...!
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (mSharedTasks) {
System.out.println(Thread.currentThread().getName()
+ " consumed " + mSharedTasks.poll());
if (mSharedTasks.size() == ProducerConsumerProblem.CAPACITY - 1)
mSharedTasks.notifyAll();
}
}
}
}
}
public class ProducerConsumerTest {
public static void main(String[] args) {
CubbyHole c = new CubbyHole();
Producer p1 = new Producer(c, 1);
Consumer c1 = new Consumer(c, 1);
p1.start();
c1.start();
}
}
class CubbyHole {
private int contents;
private boolean available = false;
public synchronized int get() {
while (available == false) {
try {
wait();
} catch (InterruptedException e) {
}
}
available = false;
notifyAll();
return contents;
}
public synchronized void put(int value) {
while (available == true) {
try {
wait();
} catch (InterruptedException e) {
}
}
contents = value;
available = true;
notifyAll();
}
}
class Consumer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Consumer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
int value = 0;
for (int i = 0; i < 10; i++) {
value = cubbyhole.get();
System.out.println("Consumer #"
+ this.number
+ " got: " + value);
}
}
}
class Producer extends Thread {
private CubbyHole cubbyhole;
private int number;
public Producer(CubbyHole c, int number) {
cubbyhole = c;
this.number = number;
}
public void run() {
for (int i = 0; i < 10; i++) {
cubbyhole.put(i);
System.out.println("Producer #" + this.number
+ " put: " + i);
try {
sleep((int) (Math.random() * 100));
} catch (InterruptedException e) {
}
}
}
}
Please copy the program below and try running in your IDE. It's a simple Produce Consumer implementation - it runs fine when I use one Producer and one Consumer thread but fails when using 2 each. Please let me know the reason why this program hangs or is there anything else wrong with it.
import java.util.LinkedList;
import java.util.Queue;
public class PCQueue {
private volatile Queue<Product> productQueue = new LinkedList<Product>();
public static void main(String[] args) {
PCQueue pc = new PCQueue();
Producer producer = new Producer(pc.productQueue);
Consumer consumer = new Consumer(pc.productQueue);
new Thread(producer, "Producer Thread 1").start();
new Thread(consumer, "Consumer Thread 1").start();
new Thread(producer, "Producer Thread 2").start();
new Thread(consumer, "Consumer Thread 2").start();
}
}
class Producer implements Runnable {
private Queue<Product> queue = null;
private static volatile int refSerialNumber = 0;
public Producer(Queue<Product> queue) {
this.queue = queue;
}
#Override
public void run() {
while (true) {
synchronized (queue) {
while (queue.peek() != null) {
try {
queue.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
queue.add(new Product(++refSerialNumber));
System.out.println("Produced by: "
+ Thread.currentThread().getName() + " Serial Number: "
+ refSerialNumber);
queue.notify();
}
}
}
}
class Consumer implements Runnable {
private Queue<Product> queue = null;
public Consumer(Queue<Product> queue) {
this.queue = queue;
}
#Override
public void run() {
while (true) {
synchronized (queue) {
while (queue.peek() == null) {
try {
queue.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Product product = queue.remove();
System.out.println("Consumed by: "
+ Thread.currentThread().getName() + " Serial Number: "
+ product.getSerialNumber());
queue.notify();
}
}
}
}
class Product {
private int serialNumber;
public Product(int serialNumber) {
this.serialNumber = serialNumber;
}
public int getSerialNumber() {
return serialNumber;
}
}
The problem is that you are using queue.notify() which will only wake up a single Thread waiting on the Queue. Imagine Producer 1 calls notify() and wakes up Producer 2. Producer 2 sees that there is something in the queue so he doesn't produce anything and simply goes back to the wait() call. Now both your Producers and Consumers are all waiting to be notified and nobody is left working to notify anyone.
To solve the problem in your code, use queue.notifyAll() to wake up every Thread blocked at a wait(). This will allow your consumers to run.
As a note, your implementation limits the queue to having at most one item in it. So you won't see any benefit from the second set of producers and consumers. For a better all around implementation, I suggest you look at BlockingQueue and use an implementation which can be bounded, for instance, the ArrayBlockingQueue. Instead of synchronizing and using wait/notify, simply use BlockingQueue.offer() and BlockingQueue.take().
instead of queue.notify() use queue.notifyAll()