Creating a Synchronized Buffer for Producer/Consumer pattern in Java - java

I implemented a buffer for the producer/consumer pattern, however, it seems that the Consumer never acquires the lock so Starvation occurs. I can't identify why this happens since both put() and take() seem to release the lock properly...
I know there is BlockingQueue and other nice implementations, but I want to implement this using wait() and notify() as an exercise.
public class ProducerConsumerRaw {
public static void main(String[] args) {
IntBuffer buffer = new IntBuffer(8);
ConsumerRaw consumer = new ConsumerRaw(buffer);
ProducerRaw producer = new ProducerRaw(buffer);
Thread t1 = new Thread(consumer);
Thread t2 = new Thread(producer);
t1.start();
t2.start();
}
}
class ConsumerRaw implements Runnable{
private final IntBuffer buffer;
public ConsumerRaw(IntBuffer b){
buffer = b;
}
public void run() {
while(!buffer.isEmpty()) {
int i = buffer.take();
System.out.println("Consumer reads "+i); // this print may not be in the order
}
}
}
class ProducerRaw implements Runnable{
private final IntBuffer buffer;
ProducerRaw(IntBuffer b) {
this.buffer = b;
}
public void run(){
for (int i = 0; i < 20; i++) {
int n = (int) (Math.random()*100);
buffer.put(n);
System.out.println("Producer puts "+n);
}
}
}
class IntBuffer{
private final int[] storage;
private volatile int end;
private volatile int start;
public IntBuffer(int size) {
this.storage = new int[size];
end = 0;
start = 0;
}
public void put(int n) { // puts add the END
synchronized(storage) {
boolean full = (start == (end+storage.length+1)%storage.length);
while(full){ // queue is full
try {
storage.notifyAll();
storage.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.storage[end] = n;
end = incrementMod(end);
storage.notifyAll();
}
}
public int take(){
synchronized(storage) {
while (end == start) { // empty queue
try {
storage.notifyAll(); // notify waiting producers
storage.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
int index = start;
start = incrementMod(start);
storage.notifyAll(); // notify waiting producers
return this.storage[index];
}
}
private int incrementMod(int index) {
synchronized (storage) {
if (index == storage.length-1) return 0;
else return index+1;
}
}
public boolean isEmpty(){
synchronized (storage) {
return (start == end);
}
}
}

This is at least one problem, in your put method:
boolean full = (start == (end+storage.length+1)%storage.length);
while(full){ // queue is full
// Code that doesn't change full
}
If full is ever initialized as true, how do you expect the loop to end?
The other problem is this loop, in the consumer:
while(!buffer.isEmpty()) {
int i = buffer.take();
System.out.println("Consumer reads "+i);
}
You're assuming the producer never lets the buffer get empty - if the consumer starts before the producer, it will stop immediately.
Instead, you want some way of telling the buffer that you've stopped producing. The consumer should keep taking until the queue is empty and won't receive any more data.

Related

Java producer consumer stop consumer threads

I have this piece of code and I want a good method to stop the consumer threads:
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;
public class Foo {
private final Queue<Object> queue;
private final AtomicBoolean doneReading;
private final int numberOfThreads = 4, N = 100;
public Foo() {
queue = new ArrayDeque<>();
doneReading = new AtomicBoolean(false);
}
public void execute() throws InterruptedException {
Thread[] threads = new Thread[numberOfThreads];
for (int i = 0; i < numberOfThreads; i++) {
threads[i] = new Thread(() -> {
try {
synchronized (queue) {
while (!doneReading.get() || !queue.isEmpty()) {
if (queue.isEmpty()) {
queue.wait();
if (!queue.isEmpty()) {
Object element = queue.remove();
// Do stuff
}
}
else {
Object element = queue.remove();
// Do stuff
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
threads[i].start();
}
for (int i = 0; i < N; i++) {
synchronized (queue) {
queue.add(new Object());
queue.notifyAll();
}
}
doneReading.set(true);
synchronized (queue) {
queue.notifyAll();
}
for (Thread thread : threads) {
thread.join();
}
}
}
Basically, when I have read all the data that needs to be processed, I want the consumer threads to stop. I tried while(!doneReading.get()) but this does not guarantee that there aren't any leftover items in the queue. I added !queue.isEmpty(), but in this case some threads keep on waiting even though they won't receive any notification. So I managed that I should call notifyAll() once more. This does seem to work. I also thought of adding a null in the queue, and whenever the consumer reads a null, it exits the while. Which method is better, or are there any better ideas?
One usual method is a "poison pill". Put a special value in the queue that when read kills the consumer threads. This allows them to process all of the values and not stop until they read past the final value and read the poison pill.
Some more info: https://java-design-patterns.com/patterns/poison-pill/
I also like these websites, they often have thoughtful information on Java programming:
https://mkyong.com/java/java-blockingqueue-examples/
https://www.baeldung.com/java-blocking-queue
class LimitedQueue<T> {
ArrayDeque<T> queue = new ArrayDeque<>();
boolean done = false;
synchronized void add (T item) {
queue.add(item);
notifyAll();
}
synchronized void done()
done=true;
notifyAll();
}
// most complex method
// waits until next item or done signal is put
synchronized boolean isDone() {
for (;;) {
if (!queue.isEmpty(){
return false;
}
if (done) {
return true;
}
wait();
}
}
syncronized T remove() {
return deque.remove();
}
}
LimitedQueue<Object> queue = new LimitedQueue<>();
class ConsumerThread extends Thread {
public void run(){
while (!queue.isDone()) {
Object element = queue.remove();
// do stuff
}
}
}
class ProducerThread extends Thread {
public void run() {
for (int i = 0; i < N; i++) ,{
queue.add(new Object());
}
queue.done();
}
}

Java - How to detect deadlocks and recovery from this?

Right now I write a Java program that has as purpose detect deadlocks and recovery from this situation. The program input is two numbers, N = Number of types of resources and M = Number of process.
I wanted to do something like this:
private static void test2() {
final ReentrantLock lock1 = new ReentrantLock();
final ReentrantLock lock2 = new ReentrantLock();
Thread thread1 = new Thread(new Runnable() {
#Override public void run() {
try {
lock1.lock();
System.out.println("Thread1 acquired lock1");
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException ignore) {}
lock2.lock();
System.out.println("Thread1 acquired lock2");
}
finally {
lock2.unlock();
lock1.unlock();
}
}
});
thread1.start();
Thread thread2 = new Thread(new Runnable() {
#Override public void run() {
try {
lock2.lock();
System.out.println("Thread2 acquired lock2");
try {
TimeUnit.MILLISECONDS.sleep(50);
} catch (InterruptedException ignore) {}
lock1.lock();
System.out.println("Thread2 acquired lock1");
}
finally {
lock1.unlock();
lock2.unlock();
}
}
});
thread2.start();
// Wait a little for threads to deadlock.
try {
TimeUnit.MILLISECONDS.sleep(100);
} catch (InterruptedException ignore) {}
detectDeadlock();
}
But instead of 2, N locks and I have several problems for doing this. Here my code with my attempt:
class Main {
private static int MAX_AVAILABLE = 10;
private static int IDLE = 1000;
public static void main(String[] args) throws java.lang.Exception{
int n, m; //number of resources and process, respectively
ReentrantLock[] resources; // Locks for resources
int[] available; // Number of instances per resource
Process[] processes; // Processes array
DeadlockDetector supervisor; // Deadlock detaction class
n = Integer.valueOf(args[0]);
m = Integer.valueOf(args[1]);
resources = new ReentrantLock[n];
available = new int[n];
processes = new Process[m];
supervisor = new DeadlockDetector();
// Create resources array
for(int i=0; i<n; ++i){
available[i] = (int)(Math.floor(Math.random()*MAX_AVAILABLE + 1));
resources[i] = new ReentrantLock();
System.out.println("R"+String.valueOf(i+1)+"-> instances: "+String.valueOf(available[i]));
}
// Creating processes
for(int i=0; i<m; ++i){
processes[i] = new Process(i, resources, available, n);
System.out.println("P"+String.valueOf(i+1)+"-> requested "+Arrays.toString(processes[i].requested));
processes[i].start();
}
//Run deadlock detection
try {
TimeUnit.MILLISECONDS.sleep(IDLE);
}catch (InterruptedException ignore){}
supervisor.start();
}
}
class Process extends Thread{
public int id;
public int total; // Total of resources instances needed for finished the process
public ReentrantLock[] resources;
public int[] requested; // Number of instances needed per resource type
public boolean[] needed; // Boolean indicating whether the process needs at least one instance of the resource i
public int n;
private static int MIN_TIME = 1000;
private static int MAX_TIME = 3000;
public Process(int index, ReentrantLock[] res, int[] available, int n_resources){
id = index;
n = n_resources;
resources = res;
total = 0;
requested = new int[n];
needed = new boolean[n];
for(int i=0; i<n; ++i){
requested[i] = (int)(Math.floor(Math.random()*available[i]));
needed[i] = requested[i] > 0;
total += requested[i];
}
}
#Override
public void run(){
int resourceT = 0;
int timeToSleep;
System.out.println("P"+String.valueOf(id+1)+" begin running");
try{
while(total > 0){
resourceT = (int)(Math.floor(Math.random()*n));
if(requested[resourceT] < 1){
System.out.println("P"+String.valueOf(id+1)+"-> I do not need more R"+String.valueOf(resourceT+1));
continue;
}
System.out.println("P"+String.valueOf(id+1)+"-> I'll take R"+String.valueOf(resourceT+1));
resources[resourceT].lock();
timeToSleep = (int)(Math.floor(Math.random()*(MAX_TIME - MIN_TIME)) + MIN_TIME);
try{
TimeUnit.MILLISECONDS.sleep(timeToSleep);
}catch (InterruptedException ignore){}
--total;
--requested[resourceT];
}
}finally{
for(int i=0; i<n; ++i){
if(needed[i] && resources[i].isHeldByCurrentThread())
resources[i].unlock();
}
}
System.out.println("P"+String.valueOf(id+1)+"-> Im finished");
}
}
class DeadlockDetector extends Thread{
public ThreadMXBean threadBean;
public long[] threadIds;
public DeadlockDetector(){
}
#Override
public void run(){
Boolean good;
this.threadBean = ManagementFactory.getThreadMXBean();
threadIds = threadBean.findDeadlockedThreads();
int deadlockedThreads = threadIds != null? threadIds.length : 0;
if(deadlockedThreads>1){
good = false;
System.out.println("Number of deadlocked threads: " + deadlockedThreads);
//recoverDeadlock();
//break;
}
}
public void recoverDeadlock(){
}
}
Please, could anyone help me fix this detail? Thanks!

Can't understand barrier code

I ran across this barrier code and I cannot understand the barrierPost method.
Im supposed to use this code to solve an exercise where two teams of threads race eachother to count to 10000.
I don't understand why the same condition has different results which are opposite
public class Barrier {
private int currentPosters = 0, totalPosters = 0;
private int passedWaiters = 0, totalWaiters = 1;
/**
* #param totalPosters - Nr of threads required to start the waiting threads
* #param totalWaiters - Nr of threads started later
*/
public Barrier (int totalPosters, int totalWaiters) {
this.totalPosters = totalPosters;
this.totalWaiters = totalWaiters;
}
public synchronized void init(int i) {
totalPosters = i; currentPosters=0;
}
public synchronized void barrierSet(int i) {
totalPosters = i; currentPosters=0;
}
public synchronized void barrierWait() {
boolean interrupted = false;
while (currentPosters = totalPosters) {
try {wait();}
catch (InterruptedException ie) {interrupted=true;}
}
passedWaiters++;
if (passedWaiters == totalWaiters) {
currentPosters = 0; passedWaiters = 0; notifyAll();
}
if (interrupted) Thread.currentThread().interrupt();
}
public synchronized void barrierPost() {
boolean interrupted = false; // In case a poster thread beats barrierWait, keep count of posters.
while (currentPosters == totalPosters) {
try {wait();}
catch (InterruptedException ie) {interrupted=true;}
}
currentPosters++;
if (currentPosters == totalPosters) notifyAll();
if (interrupted) Thread.currentThread().interrupt();
}
}
Can someone help?

adding multiple values in synchronized buffer

So I have a Producer, Consumer and a shared Synchronized buffer.
The producer creates a number (that gets saved in the buffer)
And the consumer gets 5 guesses to guess the number.
Once the consumer guesses correctly it’s asked whether it wants to play again and number of times guessed correctly is saved in the buffer.
My synchronizedBuffer class is all wrong. I don't even know where to begin to implement the second value into it. Even a little hint as to how I'm supposed to do it will be much appreciated. I'm not allowed to use array-blocking queues.
//Class: Producer
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
public class Producer implements Runnable {
private final static Random generator = new Random();
private final Buffer sharedLocation;
public Producer(Buffer shared) {
sharedLocation = shared;
}
public void run() {
try {
int x = ThreadLocalRandom.current().nextInt(1, 10);
Thread.sleep(generator.nextInt(3000)); // random sleep
sharedLocation.set(x); // set value in buffer
System.out.printf("\n", x);
}
catch (InterruptedException exception) {
exception.printStackTrace();
}
System.out.println("Producer done producing");
}
}
//Class: Consumer
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
public class Consumer implements Runnable {
private final static Random generator = new Random();
private final Buffer sharedLocation;
public Consumer(Buffer shared) {
sharedLocation = shared;
}
public void run() {
int correct = 0;
outerloop: for (int i = 1; i <= 5; i++) {
try {
int x = ThreadLocalRandom.current().nextInt(1, 10);
Thread.sleep(generator.nextInt(2000));
if (x == sharedLocation.get()) {
System.out.println(x);
System.out.println("correct guess was " + x);
correct++;
sharedLocation.set(correct);
break outerloop;
}
System.out.print(x + "\n");
} catch (InterruptedException exception) {
exception.printStackTrace();
}
}
}
}
public class SynchronizedBuffer implements Buffer {
private int buffer = -1;
private boolean occupied = false;
public synchronized void set(int value) throws InterruptedException {
while (occupied) {
System.out.println("Producer tries to write.");
System.out.println("Consumer tries to guess");
wait();
} // end while
buffer = value;
occupied = true;
displayState("Producer writes " + buffer);
notifyAll();
buffer = value;
}
public synchronized int get() throws InterruptedException {
while (!occupied) {
System.out.println("Consumer tries to guess.");
displayState("Buffer empty. Consumer waits.");
wait();
}
occupied = false;
notifyAll();
return buffer;
}
public void displayState(String operation) {
System.out.printf("%-40s%d\t\t%b\n", operation, buffer, occupied);
}
}

Producer Consumer using threads

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) {
}
}
}
}

Categories

Resources