Deadlocking threads

S

Sunitha Kumar

Hi,

I've implemented a Fixed Queue that contains even and odd Integers with one
each EvenProducer, EvenConsumer. OddProducer, OddConsumer threads, all
capable of producing and consuming ten even or odd Integers each. My problem
is that my threads stop consuming after a certain point (the 7th iteration,
according to my debugger) and I can't figure out why. (I've used different
sleep times, synchronized all methods to no avail.)

I've attached my code below:
/**
* EvenConsumer
* @
*/
public class EvenConsumer extends Thread
{
private FixedQueue queue;
private int number;
private int workCount;
public EvenConsumer(FixedQueue q, int i)
{
this.queue= q;
this.number= i;
}
public void run()
{
try
{
for (int i= 0; i < 10; i++)
{
Integer value= queue.evenDequeue();
System.out.println(
"Even Consumer #" + this.number + " removed " + value);
System.out.println(queue.toString());
trackWorkPerformance(i);
sleep((int) (Math.random() * 20));
}
generatePerformanceReport(this.workCount);
}
catch (InterruptedException e)
{
}
}
private void trackWorkPerformance(int i)
{
workCount= i + 1;
}
private void generatePerformanceReport(int workCount)
{
System.out.println(
"Even Consumer #"
+ this.number
+ " has been working "
+ workCount
+ " times.");
}
}

/**
* EvenProducer
* @ Places randomly generated even Integer objects into
* the rear of a FixedQueue.
*/
public class EvenProducer extends Thread
{
private FixedQueue queue;
private int number;
private int workCount;
public EvenProducer(FixedQueue q, int i)
{
this.queue= q;
this.number= i;
}
public void run()
{
try
{
for (int i= 0; i < 10; i++)
{
int value= Random.nextEvenInt();
queue.evenEnqueue(new Integer(value));
//System.out.println(value);
System.out.println(
"Even Producer #" + this.number + " put " + value);
System.out.println(queue.toString());
trackWorkPerformance(i);
sleep((int) (Math.random() * 30));
}
generatePerformanceReport(this.workCount);
}
catch (InterruptedException e)
{
}
}
private void trackWorkPerformance(int i)
{
workCount= i + 1;
}
private void generatePerformanceReport(int workCount)
{
System.out.println(
"Even Producer #"
+ this.number
+ " has been working "
+ workCount
+ " times.");
}
}

/**
* OddConsumer
* @
*/
public class OddConsumer extends Thread
{
private FixedQueue queue;
private int number;
private int workCount;
public OddConsumer(FixedQueue q, int i)
{
this.queue= q;
this.number= i;
}
public void run()
{
try
{
for (int i= 0; i < 10; i++)
{
Integer value= queue.oddDequeue();
System.out.println(
"Odd Consumer #" + this.number + " removed " + value);
System.out.println(queue.toString());
trackWorkPerformance(i);
sleep((int) (Math.random() * 10));
}
generatePerformanceReport(this.workCount);
}
catch (InterruptedException e)
{
}
}
private void trackWorkPerformance(int i)
{
workCount= i + 1;
}
private void generatePerformanceReport(int workCount)
{
System.out.println(
"Odd Consumer #"
+ this.number
+ " has been working "
+ workCount
+ " times.");
}
}

/**
* OddProducer
* @
*/
public class OddProducer extends Thread
{
private FixedQueue queue;
private int workCount;
private int number;
public OddProducer(FixedQueue q, int i)
{
this.queue= q;
this.number= i;
}
public void run()
{
try
{
for (int i= 0; i < 10; i++)
{
int value= Random.nextOddInt();
queue.oddEnqueue(new Integer(value));
//System.out.println(value);
System.out.println(
"OddProducer #" + this.number + " put " + value);
System.out.println(queue.toString());
trackWorkPerformance(i);
sleep((int) (Math.random() * 10));
}
generatePerformanceReport(this.workCount);
}
catch (InterruptedException e)
{
}
}
private void trackWorkPerformance(int i)
{
workCount = i+1;
}

private void generatePerformanceReport(int workCount)
{
System.out.println(
"Odd Producer #"
+ this.number
+ " has been working "
+ workCount
+ " times.");
}
}

/**
* FixedQueue
* @
*/
public class FixedQueue
{
private static FixedQueue singleton= new FixedQueue();
private boolean evenAvailable= false;
private Integer num, value;
private boolean oddAvailable= false;
private final LinkedList queue= new LinkedList();
private int queueSize= 5;
public synchronized Integer evenDequeue() throws InterruptedException
{
while ((evenAvailable == false) || (isEmpty()) || (isOdd()))
{
wait();
}
value= (Integer) queue.removeFirst();
evenAvailable= false;
notifyAll();
return value;
}
public synchronized void evenEnqueue(Integer i) throws
InterruptedException
{
while (isFull())
{
wait();
}
queue.addLast(i);
evenAvailable= true;
notifyAll();
}
/**
* @param num
* @return
*/
private synchronized boolean isEven()
{
Integer value= (Integer) queue.get(0);
return value.intValue() % 2 == 0;
}
private synchronized boolean isFull()
{
return (queueSize == queue.size());
}
public synchronized boolean isEmpty()
{
return (queue.size() == 0);
}
public synchronized boolean isOdd()
{
Integer value= (Integer) queue.get(0);
return value.intValue() % 2 == 1;
}
public synchronized Integer oddDequeue()
{
while ((oddAvailable == false) || (isEmpty()) || (isEven()))
{
try
{
wait();
}
catch (InterruptedException e)
{
}
}
value= (Integer) queue.removeFirst();
oddAvailable= false;
notifyAll();
return value;
}
public synchronized void oddEnqueue(Integer i)
{
while (isFull())
{
try
{
wait();
}
catch (InterruptedException e)
{
}
}
queue.addLast(i);
oddAvailable= true;
notifyAll();
}
public synchronized String toString()
{
return queue.toString();
}
}

/**
* Random
* @ Generates random odd and even int numbers.
*/
public class Random
{
private static final java.util.Random RAND= new java.util.Random();
private static final int EVEN_MASK= -2;
private static final int ODD_MASK= 1;
public static synchronized int nextEvenInt()
{
return RAND.nextInt() & EVEN_MASK;
}
public static synchronized int nextOddInt()
{
return RAND.nextInt() | ODD_MASK;
}
}

/**
* QueueException
* @
*/
public class QueueException extends Exception
{
/**
*
*/
public QueueException()
{
super();

}
}

Any help would be appreciated!

Thanks,
Sunitha
 
J

Jon Skeet

Sunitha Kumar said:
I've implemented a Fixed Queue that contains even and odd Integers with one
each EvenProducer, EvenConsumer. OddProducer, OddConsumer threads, all
capable of producing and consuming ten even or odd Integers each. My problem
is that my threads stop consuming after a certain point (the 7th iteration,
according to my debugger) and I can't figure out why. (I've used different
sleep times, synchronized all methods to no avail.)

I haven't checked, but I *suspect* the problem is with your
evenAvailable/oddAvailable flags - there's no need for them given the
isOdd/isEven check, and you reset them after fetching an even number -
which means if there are two even numbers in a row in the queue, you'll
stop consuming until the next even number is added to the far end.

That's just a guess after reading through the code very briefly though.

I would personally have a design with two separate queues - much
simpler.
 
S

Steve Horsley

Hi,

I've implemented a Fixed Queue that contains even and odd Integers with one
each EvenProducer, EvenConsumer. OddProducer, OddConsumer threads, all
capable of producing and consuming ten even or odd Integers each. My problem
is that my threads stop consuming after a certain point (the 7th iteration,
according to my debugger) and I can't figure out why. (I've used different
sleep times, synchronized all methods to no avail.)

See my answer in another group.

Steve
 
J

Jon Skeet

Sunitha Kumar said:
Jon, I commented out the evenAvailable/oddAvailable flags to test your
theory - the threads still locked, unfortunately.

Thanks though, you're right of course - I overlooked the fact that by
testing for isOdd/isEven, the flags for oddAvailable/evenAvailable become
redundant.

Right. In that case, could you post your complete app (so we can
actually run it) after the flags have been removed (and possibly taking
into account Steve's point about using Runnable). If it's quite large,
it might be worth putting it in a zip file and putting it on a web site
somewhere. If you want to mail it to me, feel free.
Right, I wish I could too, but the single fixed queue is a requirement for
this assignment.

Does it have to be a single fixed queue in implementation, or only in
interface? In other words, is there anything to stop you from actually
having two "hidden" queues, and forwarding on the produce/consume
requests to them?
 
J

Jon Skeet

[Also replied via email]


Thanks Jon, I have mailed it to you at (e-mail address removed) (in a zipped file, of
course).

After all that, the problem (aside from the flags, which I'm sure were
also duff) is in testing for an odd number. You can't use if (x%2==1)
to test for oddity when x can be negative, as (say) -3%2 = -1, not 1.
The easiest change is to use &1 instead of %2 in this case.
 
S

Sunitha Kumar

Jon Skeet said:
[Also replied via email]

Thanks for your help - modifying the test for oddity solved the deadlock.
After all that, the problem (aside from the flags, which I'm sure were
also duff) is in testing for an odd number. You can't use if (x%2==1)
to test for oddity when x can be negative, as (say) -3%2 = -1, not 1.
The easiest change is to use &1 instead of %2 in this case.

Or even better for clarity: if (x%2!=0) to test for oddity.

:)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top