Variation on Producer / Consumer

Here is a variation on the Producer / Consumer with 4 puts and 4 gets. I don't understand why the notifyall is not causing the Saver thread to awake. I would appreciate any suggestions.

import java.util.*;

public class SpendnSave {

Float Balance = new Float(0); // Account Balance

boolean insufficient_funds;

// Constructor *******************************************************************

public SpendnSave()

{

new Spender().start(); // Spend a little

new Saver().start();// Save a little

}

// Saver *******************************************************************

class Saver extends Thread {

Float Amount;

// Constructor

Saver()

{

super();

this.Amount = 0f;

}

public void run()

{

this.deposit(100f);

this.deposit(200f);

this.deposit(300f);

this.deposit(400f);

}

synchronized void deposit(Float Amount)

{

Balance += Amount;

System.out.println("deposit is:" + Amount);

System.out.println("deposit balance is:" + Balance + " ** " + Thread.currentThread().getName());

if (Balance > 900) {

insufficient_funds = false;

System.out.println("deposit notifying..." + insufficient_funds);

notifyAll();

}

}

} // Saver

// Spender *******************************************************************

class Spender extends Thread {

Float Amount;

// Constructor

Spender()

{

super();

this.Amount = 0f;

}

public void run()

{

this.withdrawal(50f);

this.withdrawal(100f);

this.withdrawal(150f);

this.withdrawal(200f);

}

synchronized void withdrawal (Float Amount)

{

Balance -= Amount;

System.out.println("withdrawal is:" + Amount);

System.out.println("withdrawal balance is:" + Balance + " ** " + Thread.currentThread().getName());

if (Balance < 0) insufficient_funds = true;

// Insufficient Funds.....

while (insufficient_funds)

{

System.out.println("Insufficient Funds...." + Balance);

try {

System.out.println("Thread Waiting....." + insufficient_funds);

wait(); // Relinquish the lock...

// Let the Saver Thread notify when the balance is greater than zero

System.out.println("After Waiting");

}

catch (InterruptedException e)

{

System.out.println("Withdrawal permitted to continue (INTERRUPTED)");

}

insufficient_funds = false;

}

}

}

public static void main(String args[])

{

SpendnSave spendnsave = new SpendnSave();

// Slow up the main thread so we can see how many threads are active...

try {

Thread.sleep(5000);

}

catch (InterruptedException e) {}

System.out.println("Alive Threads:" + Thread.activeCount());

}

}

[2990 byte] By [skalvia] at [2007-11-27 8:26:58]
# 1
At first sight i would say you are waiting/notifying on "this" in each Thread.Which means on different objects...Try using the same object as lock. (btw think about modify your synchronizes to synchronize on the lock too).
ibanna at 2007-7-12 20:16:34 > top of Java-index,Core,Core APIs...
# 2

I tried this variation also without any success.

import java.util.*;

public class SpendSave {

Float Balance = new Float(0); // Account Balance

boolean insufficient_funds;

// Constructor *******************************************************************

public SpendSave()

{

new Spender().start(); // Spend a little

new Saver().start();// Save a little

}

// Saver *******************************************************************

class Saver extends Thread {

Float Amount;

// Constructor

Saver()

{

super();

this.Amount = 0f;

}

public void run()

{

deposit(100f);

deposit(200f);

deposit(300f);

deposit(400f);

}

void deposit(Float Amount)

{

synchronized (Balance) {

Balance += Amount;

}

System.out.println("deposit is:" + Amount);

System.out.println("deposit balance is:" + Balance + " ** " + Thread.currentThread().getName());

if (Balance > 900) {

synchronized (Balance) {

Balance.notifyAll();

insufficient_funds = false;

System.out.println("deposit notifying..." + insufficient_funds);

}

}

}

} // Saver

// Spender *******************************************************************

class Spender extends Thread {

Float Amount;

// Constructor

Spender()

{

super();

this.Amount = 0f;

}

public void run()

{

withdrawal(50f);

withdrawal(100f);

withdrawal(150f);

withdrawal(200f);

}

void withdrawal (Float Amount)

{

System.out.println("withdrawal is:" + Amount);

synchronized (Balance) {

Balance -= Amount;

System.out.println("withdrawal balance is:" + Balance + " ** " + Thread.currentThread().getName());

if (Balance < 0) insufficient_funds = true;

}

// Insufficient Funds.....

synchronized (Balance) {

while (insufficient_funds)

{

System.out.println("Insufficient Funds...." + Balance);

try {

System.out.println("Thread Waiting....." + insufficient_funds);

Balance.wait(); // Relinquish the lock...

// Let the Saver Thread notify when the balance is greater than zero

System.out.println("After Waiting");

}

catch (InterruptedException e)

{

System.out.println("Withdrawal permitted to continue (INTERRUPTED)");

}

insufficient_funds = false;

}

}

}

}

public static void main(String args[])

{

SpendSave spendnsave = new SpendSave();

// Slow up the main thread so we can see how many threads are active...

try {

Thread.sleep(5000);

}

catch (InterruptedException e) {}

System.out.println("Alive Threads:" + Thread.activeCount());

}

}

skalvia at 2007-7-12 20:16:34 > top of Java-index,Core,Core APIs...
# 3
Nevermind I figured it out. I will post the solution tomorrow.
skalvia at 2007-7-12 20:16:34 > top of Java-index,Core,Core APIs...
# 4
hummmFloat is an immutable object, so i guess when you do "+=" you create a new instance.So you loose the object you were waiting on...
ibanna at 2007-7-12 20:16:34 > top of Java-index,Core,Core APIs...
# 5

> hummm

> Float is an immutable object, so i guess when you do

> "+=" you create a new instance.

> So you loose the object you were waiting on...

Of course, with boxing. What you are doing is...

Balance = Float.valueOf( Balance.floatValue() + Amount );

It's usually good practice to make your lock objects final - that way, you can have the compiler tell you about problems!

oxbow_lakesa at 2007-7-12 20:16:34 > top of Java-index,Core,Core APIs...
# 6

Here's the solution. Let me know if there are still any problems with this code

* SpendSave.java: A variation on the consumer /

*producer problem to illustrate

*fine grained synchronization

*of threads.

public class SpendSave {

AccountBalance Balance; // Account Balance

// Constructor *******************************

public SpendSave()

{

Balance = new AccountBalance(0f);

new Spender("Spender").start(); // Spend a little

new Saver("Saver").start();// Save a little

}

// Saver *************************************

class Saver extends Thread {

Float Amount;

// Constructor

Saver(String name)

{

super(name);

this.Amount = 0f;

}

public void run()

{

deposit(100f);

deposit(200f);

deposit(300f);

deposit(400f);

}

void deposit(Float Amount)

{

System.out.println("deposit is: "

+ Amount

+ "\n");

synchronized (Balance) { // acquire lock

Balance.add(Amount);

System.out.println("deposit balance is: "

+ Balance.getBalance()

+ " ** "

+ Thread.currentThread().getName()

+ "\n");

}// lock released

synchronized (Balance) { // reacquire lock

if (!Balance.insufficient_funds()) {

Balance.notifyAll();

System.out.println("Saver thread notifying "

+ "Spender Thread..."

+ "\n");

} // lock released again

}

}

} // Saver

// Spender ***********************************

class Spender extends Thread {

Float Amount;

// Constructor

Spender(String name)

{

super(name);

this.Amount = 0f;

}

public void run()

{

withdrawal(50f);

withdrawal(100f);

withdrawal(150f);

withdrawal(200f);

}

void withdrawal (Float Amount)

{

System.out.println("withdrawal is:"

+ Amount

+ "\n");

synchronized (Balance) { // acquire lock

Balance.sub(Amount);

System.out.println("withdrawal balance is:"

+ Balance.getBalance()

+ " ** "

+ Thread.currentThread().getName()

+ "\n");

} // lock released

// Insufficient Funds.....

synchronized (Balance) { // reacquire lock

while (Balance.insufficient_funds())

{

System.out.println("Insufficient Funds: "

+ Balance.getBalance()

+ "\n");

try {

System.out.println("Spender Thread Waiting..\n");

Balance.wait(); // Relinquish the lock...

// Let the Saver Thread

// notify Spender when

// the balance is greater than zero

System.out.println("Spender Thread Released..\n");

}

catch (InterruptedException e)

{

System.out.println("Withdrawal permitted"

+ "to continue in case interrupt");

}

//insufficient_funds = false;

}

} // lock released again

}

}

public static void main(String args[])

{

SpendSave spendnsave = new SpendSave();

// Slow up the main thread so

// we can see how many threads are currently active...

try {

Thread.sleep(5000);

}

catch (InterruptedException e) {}

System.out.println("Alive Threads:" + Thread.activeCount());

}

}

/*

* AccountBalance.java: Definition of locked object

*/

public class AccountBalance extends Object {

Float balance;

public AccountBalance( Float amount)

{

this.balance = amount;

}

public Float add(Float amount)

{

this.balance += amount;

return this.balance;

}

public Float sub(Float amount)

{

this.balance -= amount;

return this.balance;

}

public Float getBalance()

{

return this.balance;

}

public boolean insufficient_funds() {

if (this.balance < 0f) return true;

else return false;

}

}

Message was edited by:

skalvi

skalvia at 2007-7-12 20:16:35 > top of Java-index,Core,Core APIs...
# 7
Don't use Float. You should be using a double or (if you want to use objects) BigDecimal.You are swallowing InterruptedExceptions inside a while loop making it impossible to interrupt the waiting process.
oxbow_lakesa at 2007-7-12 20:16:35 > top of Java-index,Core,Core APIs...
# 8

public boolean insufficient_funds() {

if (this.balance < 0f) return true;

else return false;

}

}

Can be simplified to (using standard Java naming conventions)

public boolean insufficientFunds() {

return this.balance < 0f;

}

oxbow_lakesa at 2007-7-12 20:16:35 > top of Java-index,Core,Core APIs...