I have a pretty simple problem, in wich I try to exchange an object ( in this case an array of int) between two task : Producer and Consumer. The Producer class produces an array of int and than it tries to exchange it with the Consumer array ( which is an empty array) using an Exchanger object. But it seems that it doesn't work: when the Consumer tries to print the array, it gets nothing.
public class Producer implements Runnable{
private Exchanger<List<Integer>> exchanger;
private List<Integer> ints = new ArrayList<Integer>();
public Producer(Exchanger<List<Integer>> ex) {
this.exchanger = ex;
}
public void run() {
RandomGenerator.Integer gen = new RandomGenerator.Integer();
try{
while(!Thread.interrupted()) {
for (int i = 0;i < Test.LIST_SIZE;i++)
ints.add(gen.next());
exchanger.exchange(ints);
//for(Integer x : ints)
//System.out.print(" " + x);
//System.out.println();
}
}catch(InterruptedException e) {
System.out.println("Producer interrupted");
}
}
}
public class Consumer implements Runnable {
private Exchanger<List<Integer>> exchanger;
private List<Integer> ints = new ArrayList<Integer>();
public Consumer(Exchanger<List<Integer>> ex) {
this.exchanger = ex;
}
public void run() {
try{
while(!Thread.interrupted()) {
exchanger.exchange(ints);
System.out.println("Consumer:");
for(Integer x : ints) {
System.out.print(" " + x);
ints.remove(x);
}
System.out.println();
}
} catch(InterruptedException e) {
System.out.println("Consumer interrupted");
}
}
}
public class Test {
public static final int LIST_SIZE = 10;
public static void main(String[] args) throws InterruptedException {
ExecutorService exec = Executors.newCachedThreadPool();
Exchanger<List<Integer>> exchanger = new Exchanger<List<Integer>>();
exec.execute(new Producer(exchanger));
exec.execute(new Consumer(exchanger));
TimeUnit.MILLISECONDS.sleep(5);
exec.shutdownNow();
}
If i uncomment the lines in Producer i see that the numbers generated are still there. So why does it not exchange the object?
The exchanger does not swap the references in place, but returns the exchanged object. So you should write something like:
List<Integer> received = exchanger.exchange(ints);
System.out.println("Consumer:");
for(Integer x : received) {
System.out.print(" " + x);
...
}
BTW, I don't think exchangers are appropriate for producer/consumers...
The exchange isn't magical; the Exchanger object can't replace the object references itself. The documentation tells us that calling the function returns the object that was provided by the other thread, once the exchange point was reached, which is how we "receive" it. I haven't actually done any of this, but I assume you're meant to assign this result back; i.e. ints = exchanger.exchange(ints); in both classes.
Related
Why is the following code thread unsafe?
In ConcurrentHashMap, the key is the current time, the value is MutableInteger, and the mutableInteger is used for counting, and the set method and get method have been locked. Why is the final value incorrect?
public class MutableInteger {
private volatile int value;
public MutableInteger() {
}
public synchronized int getValue() {
return value;
}
public synchronized void setValue(int value) {
this.value = value;
}
}
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.concurrent.*;
public class LinkedQueue {
static ConcurrentHashMap<String,MutableInteger> map = new ConcurrentHashMap();
public static class CountQueue{
static BlockingQueue<Calendar> queue = new LinkedBlockingQueue<Calendar>();
public void produce() throws InterruptedException{
queue.put(Calendar.getInstance());
}
public Calendar consume() throws InterruptedException{
return queue.take();
}
}
/**
*/
public static void recordFlow(){
final CountQueue queue = new CountQueue();
class Producer implements Runnable {
public void run() {
try {
queue.produce();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
class Consumer implements Runnable {
public void run() {
try {
getdata(queue.consume());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
ExecutorService service = Executors.newCachedThreadPool();
Producer producer = new Producer();
Consumer consumer = new Consumer();
service.submit(producer);
service.submit(consumer);
service.shutdown();
}
/**
*
*
* #param c 队列中取出的时间
*/
public static void getdata(Calendar c){
try{
saveFlow(c);
}catch (Exception e){
e.printStackTrace();
}
}
// 接口流量记录
public static void saveFlow(Calendar c){
System.out.println("Thread Name:"+Thread.currentThread().getName());
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdfHour = new SimpleDateFormat("yyyy-MM-dd HH");
SimpleDateFormat sdfMinute = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String dayAcceptKey = sdfDate.format(c.getTime());
String hourAcceptKey = sdfHour.format(c.getTime());
String minuteAcceptKey = sdfMinute.format(c.getTime());
MutableInteger newMinuteAcceptKey = new MutableInteger();
newMinuteAcceptKey.setValue(1);
MutableInteger oldMinuteAcceptKey = map.put(minuteAcceptKey, newMinuteAcceptKey);
if(null != oldMinuteAcceptKey) {
newMinuteAcceptKey.setValue(oldMinuteAcceptKey.getValue() + 1);
}
System.out.println("minute in map:"+ minuteAcceptKey + ","+ newMinuteAcceptKey.getValue());
MutableInteger newHourAcceptKey = new MutableInteger();
newHourAcceptKey.setValue(1);
MutableInteger oldHourAcceptKey = map.put(hourAcceptKey, newHourAcceptKey);
if(null != oldHourAcceptKey) {
newHourAcceptKey.setValue(oldHourAcceptKey.getValue() + 1);
}
System.out.println("hour in map:" + hourAcceptKey + "," + newHourAcceptKey.getValue());
MutableInteger newDayAcceptKey = new MutableInteger();
newDayAcceptKey.setValue(1);
MutableInteger oldDayAcceptKey = map.put(dayAcceptKey, newDayAcceptKey);
if(null != oldDayAcceptKey) {
newDayAcceptKey.setValue(oldDayAcceptKey.getValue() + 1);
}
System.out.println("day in map:" + dayAcceptKey + "," + newDayAcceptKey.getValue());
}
public static void main(String[] args){
for(int i=0;i<1000;i++) {
recordFlow();
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("==========================");
for(String key:map.keySet()){
System.out.println("key and value:" +key + " " + map.get(key).getValue());
}
}
}
The get method and set method in MutableInteger have been locked and are used ConcurrentHashMap, but the result data in the main method is incorrect. Please help me see what the problem is,thank you
You've got the same issue repeatedly, which is that you are interacting with a shared data structure in a non-synchronized way. The fact that map is a ConcurrentHashMap means that individual .get and .put calls will not break thread safety, you use multiple of those calls with the assumption that the map doesn't change between them.
MutableInteger newMinuteAcceptKey = new MutableInteger();
newMinuteAcceptKey.setValue(1);
MutableInteger oldMinuteAcceptKey = map.put(minuteAcceptKey, newMinuteAcceptKey);
// let's assume here something happens
if(null != oldMinuteAcceptKey) {
newMinuteAcceptKey.setValue(oldMinuteAcceptKey.getValue() + 1);
}
If at the point marked with a comment above some other thread also puts a new MutableInteger into the map, then your later change to newMinuteAcceptKey (which should really be newMinuteAcceptValue, since it's not the key!) will be irrelevant, as that value is no longer in the map.
In order to fix this, replace this whole thing with a single compute or merge call. Then you also don't really need MutableInteger, but can switch to a boring old Integer, if you want:
map.merge(minuteAcceptKey, 1, Integer::sum);
Those methods will do the whole operation in an atomic way, i.e. make sure that no other calls manipulate the data until they are complete.
A short summary: If you need a ConcurrentHashMap, then you almost never want to have plain .put() calls (except maybe when populating the initial values in a single-threaded way), as those method have rather weak concurrency guarantees (i.e. they only guarantee to not break the map, but any other operation can easily overwrite their values at any time).
I want to use data structure which can be constantly accesed by multithreaded code . Please let me know any Data structure in java , where I can wait and use notify options . Kindly see the below code , why run method of CDRemove doesnot print all values
public class ConcurrencyDemo {
public static void main(String[] args) throws InterruptedException {
CopyOnWriteArrayList<String> threadSafeList = new CopyOnWriteArrayList<String>();
CDInsert cd1 = new CDInsert(threadSafeList);
CDRemove cr1 = new CDRemove(threadSafeList);
cd1.start();
cr1.start();
}
}
class CDInsert extends Thread
{
List threadSafeList;
public CDInsert(List threadSafeList) {
this.threadSafeList = threadSafeList;
}
public void run()
{
int counter = 0;
while(counter < 20){
counter++;
threadSafeList.add(String.valueOf(counter));
System.out.println("Counter value is "+counter);
}
}
public void showItem(){
Iterator<String> failSafeIterator = threadSafeList.iterator();
while(failSafeIterator.hasNext()){
System.out.printf("Read from CopyOnWriteArrayList : %s %n", failSafeIterator.next());
}
}
}
class CDRemove extends Thread {
List threadSafeList;
public CDRemove(List threadSafeList) {
this.threadSafeList = threadSafeList;
}
public void run(){
Iterator<String> failSafeIterator = threadSafeList.iterator();
System.out.println("Fail Safe Iterator is "+failSafeIterator);
while(true){
System.out.println("Fail Safe Iterator is "+failSafeIterator);
while(failSafeIterator.hasNext()){
System.out.printf("Read from CopyOnWriteArrayList : %s %n", failSafeIterator.next());
}
}
}
}
thread CDRemove has an infinite loop:
while(true){ // Change this.
while(failSafeIterator.hasNext()){
System.out.printf("Read from CopyOnWriteArrayList : %s %n", failSafeIterator.next());
}
}
Now the iterator will represent the state of the list when constructed. If the CDInsert thread was still running, the iterator would not have all the elements.
I want to be able to print Fibonacci series using threads, so I'm creating 2 threads:
A producer which will fill the array according to the formula f(n) = f(n-1)+f(n-2)
A consumer that will print the elements that has been calculated so far
I will set the shared array to be able to store only 5 elements at time, and the consumer will free up space in the array, allowing the producer to add more elements.
This is my consumer code:
public class Consumer implements Runnable
{
private LinkedList<Integer> sharedArray;
public Consumer(LinkedList<Integer> array, int size, int series)
{
sharedArray = array;
}
#Override
public void run()
{
while (true)
{
try
{
print();
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void print() throws InterruptedException
{
while (true)
{
synchronized (sharedArray)
{
while (sharedArray.isEmpty())
{
try
{
sharedArray.wait();
} catch (Exception ex)
{
ex.printStackTrace();
}
}
System.out.print(sharedArray.get(0) + " ");
sharedArray.notifyAll();
}
}
}
}
And this is the producer code:
public class Producer implements Runnable
{
private LinkedList<Integer> sharedArray;
private int sharedArraySize;
private int seriesSize;
public Producer(LinkedList<Integer> array, int size, int series)
{
sharedArray = array;
sharedArraySize = size;
seriesSize = series;
}
#Override
public void run()
{
for (int i = 0; i < seriesSize; i++)
{
try
{
calculate(i);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void calculate(int n) throws InterruptedException
{
synchronized (sharedArray)
{
while (sharedArray.size() == sharedArraySize)
{
sharedArray.wait();
}
if (n == 0 || n == 1)
{
sharedArray.add(n, 1);
} else
{
sharedArray.add(n, sharedArray.get(n - 1) + sharedArray.get(n - 2));
}
sharedArray.notifyAll();
}
}
}
and the main class that starts both of the threads:
public class FibThreads
{
public static void main(String[] args)
{
int seriesSize = 18; //Integer.parseInt(args[0]);
int elementsInLine = 0;//Integer.parseInt(args[1]);
int sharedArraySize = 5;//Integer.parseInt(args[2]);
LinkedList<Integer> sharedArray = new LinkedList<Integer>();
Thread producer = new Thread(new Producer(sharedArray,sharedArraySize,seriesSize), "Producer");
Thread consumer = new Thread(new Consumer(sharedArray,sharedArraySize,seriesSize), "Consumer");
producer.start();
consumer.start();
System.out.println("End of main");
}
}
My problem is: After trying to run this, I get an infinite loop, because as soon as there is a new item in the array, the consumer takes it and free up space, which means the array can't really be filled with items because the consumer frees it immediately.
How can I make it work?
Your new problem with the only "1" output is because .get() does the same like peekFirst you get the first element but it does not remove it!
What I assume you want is System.out.print(sharedArray.pollFirst() + " "); which retrives the first element and removes it from the linked list.
Your Error was probably because you removed a node but you did not updated n in your producer which then pointed to the wrong index as it should be -1 for every removed element.
EDIT: Something you should also check is that your consumer does not remove all elements as you need at least 2 to calculate the next fibonacci number!
EDIT 2: something like
while (sharedArray.isEmpty()||sharedArray.size()<=2)
{
try
{
sharedArray.wait();
} catch (Exception ex)
{
ex.printStackTrace();
}
}...
And you need update N in your producer, you could change it to sharedArray.add(sharedArray.size(),sharedArray.size()-1+sharedArray.size()-2); so you would never go out of bounderys.
You can do this because you already check beforehand if you reached the limitation and n isn't needed at all.
EDIT 3:
sharedArray.add(sharedArray.size(),sharedArray.size()-1+sharedArray.size()-2);
should be
sharedArray.add(sharedArray.size(),sharedArray.get(sharedArray.size()-1)+sharedArray.get(sharedArray.size()-2));
My bad should have mentioned that....
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) {
}
}
}
}
class NaiveSQ<E> {
boolean putting = false;
E item = null;
public synchronized E take() throws InterruptedException {
while (item == null)
wait();
E e = item;
item = null;
notifyAll();
return e;
}
public synchronized void put (E e) throws InterruptedException {
if (e == null)
return;
while (putting)
wait();
putting = true;
item = e;
notifyAll();
while (item != null)
wait();
putting = false;
notifyAll();
}
}
class Producer implements Runnable {
int id = -1;
int limit = 1;
Producer(int x) {
id = x;
}
public void run() {
System.out.printf("I am producer number %d\n", id);
for (int i=0; i<limit; i++) {
Integer I = new Integer(i);
try {
Test.queue.put(I);
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
class Consumer implements Runnable {
int id = -1;
Consumer(int x) {
id = x;
}
public void run() {
try {
Integer I = Test.queue.take();
System.out.printf(
"I am consumer number %d - I read %d\n", id, I.intValue());
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
public class Test{
static NaiveSQ<Integer> queue;
public static void main (String [] args){
System.out.println("hello from Java");
Thread p = new Thread(new Producer(1));
p.start();
for (int i=0; i<1; i++) {
Thread c = new Thread(new Consumer(i));
c.start();
}
}
};
Also why does the exception contain null?
This is an implementation from http://www.cs.rice.edu/~wns1/papers/2006-PPoPP-SQ.pdf listing 3
I get output as
hello from Java
I am producer number 1
null
null
why do I get null?
You haven't initated the queue in your main method. I guess you get a NullPointerException since the queue object is never created and the Producer and Consumer refers to the queue which is null.
Even if you initialize the queue properly, still your implementation has a major issue. If the Consumer thread tries to take an item when the queue is empty (which is totally possible according to your code), then Consumer thread enters into an indefinite wait holding the lock to the object. Producer thread can never put an item to the queue. The whole thing will halt.