new to multithreading. I wrote this program which should be a solution to the producer-consumer problem. The problem is that both a producer and a consumer end up in the waiting state. What seems to be wrong? (And everything else what is wrong ^_^) Thanks in advance.
Main class:
package producer.consumer2;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Buffer<Integer> bf = new Buffer<>(10);
Producer prod = new Producer(bf);
Consumer cons = new Consumer(bf);
prod.setConsumer(cons);
cons.setProducer(prod);
new Thread(prod).start();
new Thread(cons).start();
if(quitInput()) {
prod.terminate();
cons.terminate();
}
}
private static boolean quitInput() {
Scanner sc = new Scanner(System.in);
String line = sc.nextLine();
do {
if(line.toLowerCase().equals("q") || line.toLowerCase().equals("quit")) {
sc.close();
return true;
}
line = sc.nextLine();
} while(true);
}
}
Buffer class:
package producer.consumer2;
import java.util.ArrayList;
public class Buffer<E> {
private final int MAX_LENGTH;
private ArrayList<E> values;
public Buffer(int length){
MAX_LENGTH = length;
values = new ArrayList<E>(length);
}
public synchronized void add(E e) {
if(values.size() < MAX_LENGTH) {
values.add(e);
System.out.println(values);
} else {
throw new RuntimeException("Buffer is full at the moment.");
}
}
public synchronized boolean isEmpty() {
return values.size() == 0;
}
public synchronized boolean isFull() {
return values.size() >= MAX_LENGTH ? true : false;
}
public synchronized E remove(int index) {
E val = values.remove(index);
System.out.println(values);
return val;
}
}
Consumer class:
package producer.consumer2;
public class Consumer implements Runnable {
private final Buffer<Integer> bf;
private volatile boolean running = true;
private Producer prod;
public Consumer(Buffer<Integer> bf) {
this.bf = bf;
}
public void setProducer(Producer prod) {
this.prod = prod;
}
#Override
public void run() {
int sum = 0;
int counter = 0;
while (running) {
if (bf.isEmpty()) {
if (prod != null) {
synchronized (prod) {
prod.notify();
}
}
myWait(0);
} else {
sum += bf.remove(0);
counter++;
}
}
System.out.println("for first " + counter + " nums an avg = " + ((double) sum / counter));
}
private void myWait(long millisecs) {
System.out.println("consumer is waiting.");
try {
synchronized (this) {
this.wait(millisecs);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("consumer is NOT waiting.");
}
public void terminate() {
this.running = false;
}
}
Producer class:
package producer.consumer2;
public class Producer implements Runnable {
private final Buffer<Integer> bf;
private volatile boolean running = true;
private Consumer cons;
public Producer(Buffer<Integer> bf) {
this.bf = bf;
}
public void setConsumer(Consumer cons) {
this.cons = cons;
}
#Override
public void run() {
int counter = 1;
while (running) {
if (bf.isFull()) {
if (cons != null) {
synchronized (cons) {
cons.notify();
}
}
myWait(0);
} else {
bf.add(counter);
counter++;
}
}
}
private void myWait(long millisecs) {
System.out.println("producer is waiting.");
try {
synchronized (this) {
this.wait(millisecs);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("producer is NOT waiting.");
}
public void terminate() {
this.running = false;
}
}
Looks like a regular case of 'missed signal'. Since both consumer and producer just wait without checking a condition, yu have no way to ensure the notify actually happens during the waiting.
e.g. in Consumer :
if (prod != null) {
synchronized (prod) {
prod.notify();
}
}
myWait(0);
Note that if, after prod.notify() the Production thread does all of its work, and notifies the consumer, before it even starts waiting, the consumer will start waiting for a signal that's already been given, and missed.
Always take into account that waiting may not be needed anymore. So always check a condition before even starting to wait. In your case here, the consumer should not even begin waiting if the buffer is full. And likewise the producer should not start waiting if the buffer is empty.
It's also possible to get spurious wake ups. So you'll have to re-check the condition when returning from waiting. The typical idiom is this :
synchronized(monitor) {
while (!stateBasedCondition) {
monitor.wait();
}
}
Related
I wanted to created a program to calculate average of the numbers input through console using threading in java. In the main function I never get the output of the average value from the function getAverage(). What's wrong..When I debug..program terminates but in normal run..It should terminate when I enter anything other than double value but it does not happen.
import java.util.*;
public class P1
{
private AverageCalculator ac;
private boolean stop;
public Thread inputThread,averageThread;
public P1()
{
ac = new AverageCalculator();
new UserInteraction(ac);
new ToAverage(ac);
}
public void printAverage()
{
System.out.println("Average is " + ac.getAverage());
}
private class AverageCalculator{
private double average=0,sum=0;
private int i=0;
private boolean flag=false;
private double getAverage()
{
return average;
}
private synchronized void sum(double val) {
while(flag) {
try {
wait();
} catch(InterruptedException e) { System.out.println("Thread Interrputed"); }
}
sum += val;
i++;
flag = true;
notify();
}
private synchronized void calculateAverage()
{
while(!flag) {
try {
wait();
} catch(InterruptedException e) { System.out.println("thread interrupted"); }
}
average = (sum / i);
flag = false;
notify();
}
}
private class UserInteraction implements Runnable {
private AverageCalculator ac;
//private boolean take=true;
private double input=0;
Scanner s = new Scanner(System.in);
private UserInteraction(AverageCalculator ac) {
this.ac = ac;
inputThread = new Thread(this,"Input thread");
inputThread.start();
stop=false;
}
public void run()
{
System.out.println("Enter number: ");
while(!stop) {
if(s.hasNextDouble() == false) {
stop = true;
s.close();
}
else
{
input = s.nextDouble();
s.nextLine();
ac.sum(input);
}
}
}
}
private class ToAverage implements Runnable {
private AverageCalculator ac;
private ToAverage(AverageCalculator ac)
{
this.ac = ac;
averageThread = new Thread(this,"Average doer Thread");
averageThread.start();
}
public void run()
{
while(!stop) {
ac.calculateAverage();
}
}
}
public static void main(String[] args) {
P1 p = new P1();
try
{
p.inputThread.join();
p.averageThread.join();
} catch(InterruptedException e) { System.out.println("Interrupted in Main"); }
System.out.println("Thread input alive check: " + p.inputThread.isAlive());
System.out.println("Thread average alive check: " + p.averageThread.isAlive());
p.printAverage();
}
}
I did not totally debug your code, but the issue is that you're calling wait(). This method puts your threads into wait state and a call to notify() or notifyAll() must occur to wake your threads up.
Here is a decent explanation of what is happening when the wait() method is called:
Difference Between Wait and Sleep in Java
I want to have shared collection class which is filled by producer thread and output is shown by consumer thread. It's sometimes working with 0 element of the collection class but never goes further. In Eclipse I observer "DestroyJVM" thread after application freezes.
There is artificial latency on the producer to simulate "slow" producer. I don't have an idea why application is not working in sequence, like
"Producer acquires lock on collection class, adds Integer, consumer waits, producer releases lock, consumer acquires lock, consumer prints, consumer releases lock, producer acquires..." and so on.
Can anyone point out where is the mistake?
Here is my code:
import java.util.ArrayList;
import java.util.List;
import static java.lang.System.out;
public class SyncOwnCollMain {
public static void main(String[] args) {
SharedIntegers ints = new SharedIntegers();
Producer producer = new Producer();
Consumer consumer = new Consumer();
producer.setInts(ints);
consumer.setInts(ints);
Thread producerThread = new Thread(producer);
producerThread.setName("ProducerThread");
Thread consumerThread = new Thread(consumer);
consumerThread.setName("ConsumerThread");
producerThread.start();
consumerThread.start();
}
}
class SharedIntegers {
private final List<Integer> ints = new ArrayList<Integer>();
private final int max = 100;
public synchronized void addAtPosition(int i, Integer integer) {
ints.add(i, integer);
}
public synchronized Integer getAtPosition(int i) {
return ints.get(i);
}
public synchronized Integer removeAtPosition(int i) {
return ints.remove(i);
}
public synchronized Integer getSize() {
return ints.size();
}
public synchronized boolean isFinished() {
return max < ints.size();
}
}
class Producer implements Runnable {
private SharedIntegers ints;
private int timeout = 100;
public SharedIntegers getInts() {
return ints;
}
public void setInts(SharedIntegers ints) {
this.ints = ints;
}
#Override
public void run() {
out.println("Started ProducerThread");
if (getInts() != null) {
int i = 0;
Integer integer = null;
while (!getInts().isFinished()) {
synchronized (getInts()) {
integer = i * 3;
getInts().addAtPosition(i, integer);
out.print("Producer added new integer = " + integer + " at " + i + " position");
out.println(". Will sleep now for " + timeout + " ms");
try {
Thread.sleep(timeout);
getInts().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
}
}
}
}
class Consumer implements Runnable {
private SharedIntegers ints;
public SharedIntegers getInts() {
return ints;
}
public void setInts(SharedIntegers ints) {
this.ints = ints;
}
#Override
public void run() {
out.println("Started ConsumerThread");
if (getInts() != null && getInts().getSize() > 0) {
int i = 0;
while (!getInts().isFinished()) {
synchronized (getInts()) {
showAtPosition(i, getInts());
i++;
try {
getInts().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
Thread.yield();
}
}
} else {
Thread.yield();
}
}
private void showAtPosition(int position, SharedIntegers ints) {
out.println("sharedInts[" + position + "] -> " + ints.getAtPosition(position));
}
}
EDITED: I managed to rewrite code so that it will work in the desired manner, however, producerThread and consumerThread don't exit gracefully. Any ideas why?
import java.util.ArrayList;
import java.util.List;
import static java.lang.System.out;
public class SyncOwnCollMain {
public static void main(String[] args) {
out.println("Main application started");
SharedIntegers ints = new SharedIntegers();
Producer producer = new Producer();
Consumer consumer = new Consumer();
producer.setInts(ints);
consumer.setInts(ints);
Thread producerThread = new Thread(producer);
producerThread.setName("ProducerThread");
Thread consumerThread = new Thread(consumer);
consumerThread.setName("ConsumerThread");
consumerThread.start();
try {
Thread.sleep(1000); // simulate that consumerThread is "anxious" to start
} catch (InterruptedException e) {
e.printStackTrace();
}
producerThread.start();
try {
consumerThread.join(); //let consumerThread finish before main()
producerThread.join(); //let producerThread finish before main()
} catch (InterruptedException e) {
e.printStackTrace();
}
out.println("Main application finished");
}
}
class SharedIntegers {
private final List<Integer> ints = new ArrayList<Integer>();
private final int max = 5;
public synchronized void addAtPosition(int i, Integer integer) {
ints.add(i, integer);
}
public synchronized Integer getAtPosition(int i) {
return ints.get(i);
}
public synchronized Integer removeAtPosition(int i) {
return ints.remove(i);
}
public synchronized Integer getSize() {
return ints.size();
}
public synchronized boolean isFinished() {
return max <= ints.size();
}
public synchronized boolean overflow(int i) {
return i >= max;
}
}
class Producer implements Runnable {
private SharedIntegers ints;
private final int timeout = 500;
public SharedIntegers getInts() {
return ints;
}
public void setInts(SharedIntegers ints) {
this.ints = ints;
}
#Override
public void run() {
out.println("Started ProducerThread");
if (getInts() != null) {
int i = 0;
Integer integer = null;
synchronized (getInts()) {
while (!getInts().isFinished()) {
integer = i * 3;
getInts().addAtPosition(i, integer);
out.print("Producer added new integer = " + integer + " at " + i + " position");
out.println(". Will sleep now for " + timeout + " ms");
try {
getInts().notify();
getInts().wait();
Thread.sleep(timeout); // simulate "slow" producer
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
try {
getInts().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
out.println("Finished ProducerThread");
}
}
class Consumer implements Runnable {
private SharedIntegers ints;
public SharedIntegers getInts() {
return ints;
}
public void setInts(SharedIntegers ints) {
this.ints = ints;
}
#Override
public void run() {
out.println("Started ConsumerThread");
if (getInts() != null) {
synchronized (getInts()) {
int i = 0;
while (!getInts().overflow(i)) {
if (getInts().getSize() > 0) {
showAtPosition(i, getInts());
i++;
}
try {
getInts().notify();
getInts().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
out.println("Finished ConsumerThread");
}
private void showAtPosition(int position, SharedIntegers ints) {
out.println("sharedInts[" + position + "] -> " + ints.getAtPosition(position));
}
}
EDIT 2: solution found : needed to notify consumerThread from producerThread that getInts() lock can be re-acquired. The working code with my comments looks like this (added some data modification by consumerThread):
import java.util.ArrayList;
import java.util.List;
import static java.lang.System.out;
public class SyncOwnCollMain {
public static void main(String[] args) {
out.println("Main application started");
SharedIntegers ints = new SharedIntegers();
Producer producer = new Producer();
Consumer consumer = new Consumer();
producer.setInts(ints);
consumer.setInts(ints);
Thread producerThread = new Thread(producer);
producerThread.setName("ProducerThread");
Thread consumerThread = new Thread(consumer);
consumerThread.setName("ConsumerThread");
consumerThread.start();
try {
Thread.sleep(1000); // simulate that consumerThread is "anxious" to start
} catch (InterruptedException e) {
e.printStackTrace();
}
producerThread.start();
try {
consumerThread.join(); //let consumerThread finish before main()
producerThread.join(); //let producerThread finish before main()
} catch (InterruptedException e) {
e.printStackTrace();
}
out.println("Main application finished"); // here, main() thread has result produced by producerThread and consumerThread
}
}
class SharedIntegers {
private final List<Integer> ints = new ArrayList<Integer>();
private final int max = 5;
public synchronized void addAtPosition(int i, Integer integer) {
ints.add(i, integer);
}
public synchronized Integer getAtPosition(int i) {
return ints.get(i);
}
public synchronized Integer removeAtPosition(int i) {
return ints.remove(i);
}
public synchronized Integer getSize() {
return ints.size();
}
public synchronized boolean isFinished() {
return max <= ints.size();
}
public synchronized boolean overflow(int i) {
return i >= max;
}
}
class Producer implements Runnable {
private SharedIntegers ints;
private final int timeout = 500;
public SharedIntegers getInts() {
return ints;
}
public void setInts(SharedIntegers ints) {
this.ints = ints;
}
#Override
public void run() {
out.println("Started ProducerThread");
if (getInts() != null) {
int i = 0;
Integer integer = null;
synchronized (getInts()) {
while (!getInts().isFinished()) {
integer = i * 3;
getInts().addAtPosition(i, integer);
out.print("Producer added new integer = " + integer + " at " + i + " position");
out.println(". Will sleep now for " + timeout + " ms");
try {
getInts().notifyAll(); // notify all threads (in this case - consumer thread) that getInts() will be available for other threads to sync and other threads are legitimate to compete for locking getInts()
getInts().wait(); // release lock for getInts()
Thread.sleep(timeout); // simulate "slow" producer
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
out.println("Finished ProducerThread while() loop");
getInts().notifyAll(); // after job is done, need to notify consumer thread that it can compete to obtain getInts() lock
}
}
}
}
class Consumer implements Runnable {
private SharedIntegers ints;
public SharedIntegers getInts() {
return ints;
}
public void setInts(SharedIntegers ints) {
this.ints = ints;
}
#Override
public void run() {
out.println("Started ConsumerThread");
if (getInts() != null) {
int i = 0;
synchronized (getInts()) {
while (!getInts().overflow(i)) {
if (getInts().getSize() > 0) {
out.println(showAtPosition(i, getInts()));
increaseAtPosition(i, getInts());
out.println("After consumer increase : " + showAtPosition(i, getInts()));
i++;
}
try {
getInts().notifyAll(); // notify all threads that other threads are legitimate to compete for getInts() lock
getInts().wait(); // release getInts() lock, wait for allowance notification
} catch (InterruptedException e) {
e.printStackTrace();
}
}
out.println("Finished ConsumerThread while() loop");
}
}
}
private String showAtPosition(int position, SharedIntegers ints) {
return "sharedInts[" + position + "] -> " + ints.getAtPosition(position);
}
private void increaseAtPosition(int position, SharedIntegers ints) {
Integer increased = ints.getAtPosition(position)+1;
ints.removeAtPosition(position);
ints.addAtPosition(position, increased);
}
}
Your call to getInts().wait(); causes each Thread to wait forever, since you never call notify() , therefore your application freezes.
See the Javadoc for java.lang.Object.wait() and java.lang.Object.notify()
Inside the Producer, change
getInts().wait()
to
getInts().notify()
I have created two runnable jobs: PrintEvenNumbersJob and PrintOddNumbersJob and spawned two threads to execute these jobs. This seems to work perfectly fine! But I smell something suspicious about this implementation. Can I have some comments and advice on this implementation?
The problem that I see with this implementation is that the program terminates only when thread1 gains the lock to the object lock first otherwise it print the odd first even second order and doesn't terminate unless I supply yet another statement "lock.notify" after for statement in PrintEvenNumbersJob (as in this implementation). My question here is how to make sure that thread1 is executed first.
public class PrintEvenNumbersJob implements Runnable {
private Object lock;
public PrintEvenNumbersJob(Object lock) {
this.lock = lock;
}
#Override
public void run() {
synchronized (lock) {
for (int i = 0; i <= 10; i += 2) {
lock.notify();
System.out.println(i);
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.notify(); // not required if thread1 gains lock first
}
}
}
public class PrintOddNumbersJob implements Runnable {
private Object lock;
public PrintOddNumbersJob(Object lock) {
this.lock = lock;
}
#Override
public void run() {
synchronized (lock) {
for (int i = 1; i < 10; i += 2) {
lock.notify();
System.out.println(i);
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.notify();
}
}
}
public class EvenOddManager {
public static void main(String[] args) {
Object lock = new Object();
PrintEvenNumbersJob printEvenNumbersJob = new PrintEvenNumbersJob(lock);
PrintOddNumbersJob printOddNumbersJob = new PrintOddNumbersJob(lock);
Thread thread1 = new Thread(printEvenNumbersJob);
Thread thread2 = new Thread(printOddNumbersJob);
thread2.start();
thread1.start();
}
}
Have you try using Semaphores? It's easier because you don't need to worry about the order that wait and notify are called (if you call notify before the wait, it's "lost")
Sample code:
import java.util.concurrent.*;
public class Test {
private final Semaphore oddJobPermits = new Semaphore(0);
private final Semaphore evenJobPermits = new Semaphore(1);
private class EvenJob implements Runnable {
public void run() {
for (int i = 0; i < 10; i++) {
try {
evenJobPermits.acquire();
System.out.println(i * 2);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
oddJobPermits.release();
}
}
}
}
private class OddJob implements Runnable {
public void run() {
for (int i = 0; i < 10; i++) {
try {
oddJobPermits.acquire();
System.out.println(i * 2 + 1);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
evenJobPermits.release();
}
}
}
}
public void run() {
new Thread(new EvenJob()).start();
new Thread(new OddJob()).start();
}
public static void main(String[] args) {
new Test().run();
}
}
I believe you will need a referee:
public class Referee {
private boolean evensTurn = true;
public void waitMyTurn(boolean even) {
synchronized(this) {
while (even != evensTurn) {
try {
wait();
} finally {
}
}
}
}
public void done() {
synchronized(this) {
evensTurn = !evensTurn;
notify();
}
}
}
public class PrintEvenNumbersJob implements Runnable {
private Referee referee;
public PrintEvenNumbersJob(Referee referee) {
this.referee = referee;
}
#Override
public void run() {
for (int i = 0; i <= 10; i += 2) {
referee.waitMyTurn(true);
System.out.println(i);
referee.done();
}
}
}
public class PrintOddNumbersJob implements Runnable {
private Referee referee;
public PrintOddNumbersJob(Referee referee) {
this.referee = referee;
}
#Override
public void run() {
for (int i = 0; i <= 10; i += 2) {
referee.waitMyTurn(false);
System.out.println(i);
referee.done();
}
}
}
I tried and tested this code. It works using Semaphore
public class TestSemaphore
{
public static void main(String[] args)
throws Exception
{
AtomicInteger count = new AtomicInteger();
Semaphore s = new Semaphore(1, true);
Semaphore t = new Semaphore(1, true);
OddNumberThread oThread = new OddNumberThread(count, s, t);
EvenNumberThread eThread = new EvenNumberThread(count, s, t);
eThread.start();
oThread.start();
}
static class EvenNumberThread
extends Thread
{
private AtomicInteger count;
private Semaphore s, t;
public EvenNumberThread(AtomicInteger pCount, Semaphore pS, Semaphore pT)
{
super("Even");
count = pCount;
s = pS;
t = pT;
}
#Override
public void run()
{
// Make this thread wait until even thread starts, Order will be incorrect if removed these lines.
s.acquireUninterruptibly();
while (count.intValue() <= 10)
{
try
{
// Double checking to make it work
s.acquireUninterruptibly();
System.out.println(getName() + " " + count.getAndIncrement());
}
finally
{
t.release();
}
}
}
}
static class OddNumberThread
extends Thread
{
private AtomicInteger count;
private Semaphore s, t;
public OddNumberThread(AtomicInteger pCount, Semaphore pS, Semaphore pT)
{
super("Odd");
count = pCount;
s = pS;
t = pT;
}
#Override
public void run()
{
// Start this thread first and start printing, Order will be incorrect if removed these lines.
t.acquireUninterruptibly();
s.release();
while (count.intValue() <= 10)
{
try
{
t.acquireUninterruptibly();
System.out.println(getName() + " " + count.getAndIncrement());
}
finally
{
s.release();
}
}
}
}
}
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) {
}
}
}
}
What should I use to get semantics equivalent to AutoResetEvent in Java?
(See this question for ManualResetEvent).
#user249654's answer looked promising. I added some unit tests to verify it, and indeed it works as expected.
I also added an overload of waitOne that takes a timeout.
The code is here in case anyone else finds it useful:
Unit Test
import org.junit.Assert;
import org.junit.Test;
import static java.lang.System.currentTimeMillis;
/**
* #author Drew Noakes http://drewnoakes.com
*/
public class AutoResetEventTest
{
#Test
public void synchronisesProperly() throws InterruptedException
{
final AutoResetEvent event1 = new AutoResetEvent(false);
final AutoResetEvent event2 = new AutoResetEvent(false);
final int loopCount = 10;
final int sleepMillis = 50;
Thread thread1 = new Thread(new Runnable()
{
#Override
public void run()
{
try {
for (int i = 0; i < loopCount; i++)
{
long t = currentTimeMillis();
event1.waitOne();
Assert.assertTrue("Time to wait should be within 5ms of sleep time",
Math.abs(currentTimeMillis() - t - sleepMillis) < 5);
Thread.sleep(sleepMillis);
t = currentTimeMillis();
event2.set();
Assert.assertTrue("Time to set should be within 1ms", currentTimeMillis() - t <= 1);
}
} catch (InterruptedException e) {
Assert.fail();
}
}
});
Thread thread2 = new Thread(new Runnable()
{
#Override
public void run()
{
try {
for (int i = 0; i < loopCount; i++)
{
Thread.sleep(sleepMillis);
long t = currentTimeMillis();
event1.set();
Assert.assertTrue("Time to set should be within 1ms", currentTimeMillis() - t <= 1);
t = currentTimeMillis();
event2.waitOne();
Assert.assertTrue("Time to wait should be within 5ms of sleep time",
Math.abs(currentTimeMillis() - t - sleepMillis) < 5);
}
} catch (InterruptedException e) {
Assert.fail();
}
}
});
long t = currentTimeMillis();
thread1.start();
thread2.start();
int maxTimeMillis = loopCount * sleepMillis * 2 * 2;
thread1.join(maxTimeMillis);
thread2.join(maxTimeMillis);
Assert.assertTrue("Thread should not be blocked.", currentTimeMillis() - t < maxTimeMillis);
}
#Test
public void timeout() throws InterruptedException
{
AutoResetEvent event = new AutoResetEvent(false);
int timeoutMillis = 100;
long t = currentTimeMillis();
event.waitOne(timeoutMillis);
long took = currentTimeMillis() - t;
Assert.assertTrue("Timeout should have occurred, taking within 5ms of the timeout period, but took " + took,
Math.abs(took - timeoutMillis) < 5);
}
#Test
public void noBlockIfInitiallyOpen() throws InterruptedException
{
AutoResetEvent event = new AutoResetEvent(true);
long t = currentTimeMillis();
event.waitOne(200);
Assert.assertTrue("Should not have taken very long to wait when already open",
Math.abs(currentTimeMillis() - t) < 5);
}
}
AutoResetEvent with overload that accepts a timeout
public class AutoResetEvent
{
private final Object _monitor = new Object();
private volatile boolean _isOpen = false;
public AutoResetEvent(boolean open)
{
_isOpen = open;
}
public void waitOne() throws InterruptedException
{
synchronized (_monitor) {
while (!_isOpen) {
_monitor.wait();
}
_isOpen = false;
}
}
public void waitOne(long timeout) throws InterruptedException
{
synchronized (_monitor) {
long t = System.currentTimeMillis();
while (!_isOpen) {
_monitor.wait(timeout);
// Check for timeout
if (System.currentTimeMillis() - t >= timeout)
break;
}
_isOpen = false;
}
}
public void set()
{
synchronized (_monitor) {
_isOpen = true;
_monitor.notify();
}
}
public void reset()
{
_isOpen = false;
}
}
class AutoResetEvent {
private final Object monitor = new Object();
private volatile boolean open = false;
public AutoResetEvent(boolean open) {
this.open = open;
}
public void waitOne() throws InterruptedException {
synchronized (monitor) {
while (open == false) {
monitor.wait();
}
open = false; // close for other
}
}
public void set() {
synchronized (monitor) {
open = true;
monitor.notify(); // open one
}
}
public void reset() {//close stop
open = false;
}
}
I was able to get CyclicBarrier to work for my purposes.
Here is the C# code I was trying to reproduce in Java (it's just a demonstration program I wrote to isolate the paradigm, I now use it in C# programs I write to generate video in real time, to provide accurate control of the frame rate):
using System;
using System.Timers;
using System.Threading;
namespace TimerTest
{
class Program
{
static AutoResetEvent are = new AutoResetEvent(false);
static void Main(string[] args)
{
System.Timers.Timer t = new System.Timers.Timer(1000);
t.Elapsed += new ElapsedEventHandler(delegate { are.Set(); });
t.Enabled = true;
while (true)
{
are.WaitOne();
Console.WriteLine("main");
}
}
}
}
and here is the Java code I came up with to do the same thing (using the CyclicBarrier class as suggested in a previous answer):
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CyclicBarrier;
public class TimerTest2 {
static CyclicBarrier cb;
static class MyTimerTask extends TimerTask {
private CyclicBarrier cb;
public MyTimerTask(CyclicBarrier c) { cb = c; }
public void run() {
try { cb.await(); }
catch (Exception e) { }
}
}
public static void main(String[] args) {
cb = new CyclicBarrier(2);
Timer t = new Timer();
t.schedule(new MyTimerTask(cb), 1000, 1000);
while (true) {
try { cb.await(); }
catch (Exception e) { }
System.out.println("main");
}
}
}
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class AutoResetEvent {
private volatile boolean _signaled;
private ReentrantLock _lock;
private Condition _condition;
public AutoResetEvent(boolean initialState) {
_signaled = initialState;
_lock = new ReentrantLock();
_condition = _lock.newCondition();
}
public void waitOne(long miliSecond) throws InterruptedException {
_lock.lock();
try {
while (!_signaled)
_condition.await(miliSecond, TimeUnit.MILLISECONDS);
_signaled = false;
} finally {
_lock.unlock();
}
}
public void waitOne() throws InterruptedException {
_lock.lock();
try {
while (!_signaled)
_condition.await();
_signaled = false;
} finally {
_lock.unlock();
}
}
public void set() {
_lock.lock();
try {
_condition.signal();
_signaled = true;
} finally {
_lock.unlock();
}
}
public void reset() {
_lock.lock();
try {
_signaled = false;
} finally {
_lock.unlock();
}
}
}
One more extension to the solution from the accepted answer in case you would like to know whether your wait finished with timeout or with event set (which is exactly what .NET AutoResetEvent does).
public boolean waitOne(long timeout) throws InterruptedException {
synchronized (monitor) {
try {
long t = System.currentTimeMillis();
while (!isOpen) {
monitor.wait(timeout);
// Check for timeout
if (System.currentTimeMillis() - t >= timeout)
break;
}
return isOpen;
}
finally {
isOpen = false;
}
}
}
I believe what you're looking for is either a CyclicBarrier or a CountDownLatch.