For some reason, my program deadlocks when I assign both condition objects to my lock object. When I comment out one of the condition objects, it does not deadlock. Is there something I’m missing when it comes to assigning multiple condition objects to a single lock object? The entirety of my code below just in case you wish to look at it in its entirety. Thank you so much for all your help and time in advance!
Focus on my BankAccount class which contains the lock and condition objects as instance fields:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class BankAccount
{
public static final double MAX_BALANCE = 100000;
private double balance;
private Lock balanceChangeLock;
private Condition sufficientFundsCondition; // signals that funds > 0 to allow withdrawal
private Condition lessThanMaxBalanceCondition; // signals that balance < 100000 to allow more deposits
/**
* Constructs a bank account with a zero balance
*/
public BankAccount()
{
balance = 0;
balanceChangeLock = new ReentrantLock();
sufficientFundsCondition = balanceChangeLock.newCondition();
lessThanMaxBalanceCondition = balanceChangeLock.newCondition();
}
/**
* deposits money into the bank account
* @param amount the amount to deposit
* @throws InterruptedException
*/
public void deposit(double amount) throws InterruptedException
{
balanceChangeLock.lock();
try
{
while(balance + amount > MAX_BALANCE)
lessThanMaxBalanceCondition.await();
System.out.print("Depositing " + amount);
double newBalance = balance + amount;
System.out.println(", new balance is " + newBalance);
balance = newBalance;
sufficientFundsCondition.signalAll();
}
finally
{
balanceChangeLock.unlock();
}
}
/**
* withdraws money from the bank account
* @param amount the amount to withdraw
* @throws InterruptedException
*/
public void withdraw(double amount) throws InterruptedException
{
balanceChangeLock.lock();
try
{
while (balance < amount)
sufficientFundsCondition.await();
System.out.print("Withdrawing " + amount);
double newBalance = balance - amount;
System.out.println(", new balance is " + newBalance);
balance = newBalance;
lessThanMaxBalanceCondition.signalAll();
}
finally
{
balanceChangeLock.unlock();
}
}
/**
* gets the current balance of the bank account
* @return the current balance
*/
public double getBalance()
{
return balance;
}
}
My Runnable objects:
/**
* a deposit runnable makes periodic deposits to a bank account
*/
public class DepositRunnable implements Runnable
{
private static final int DELAY = 1;
private BankAccount account;
private double amount;
private int count;
/**
* constructs a deposit runnable
* @param anAccount the account into which to deposit money
* @param anAmount the amount to deposit in each repetition
* @param aCount the number of repetitions
*/
public DepositRunnable(BankAccount anAccount, double anAmount, int aCount)
{
account = anAccount;
amount = anAmount;
count = aCount;
}
public void run()
{
try
{
for (int i = 0; i <= count; i++)
{
account.deposit(amount);
Thread.sleep(DELAY);
}
}
catch (InterruptedException exception)
{
}
}
}
..
/**
* a withdraw runnable makes periodic withdrawals from a bank account
*/
public class WithdrawRunnable implements Runnable
{
private static final int DELAY = 1;
private BankAccount account;
private double amount;
private int count;
/**
* constructs a withdraw runnable
* @param anAccount the account from which to withdraw money
* @param anAmount the amount to deposit in each repetition
* @param aCount the number of repetitions
*/
public WithdrawRunnable(BankAccount anAccount, double anAmount, int aCount)
{
account = anAccount;
amount = anAmount;
count = aCount;
}
public void run()
{
try
{
for (int i = 0; i <= count; i++)
{
account.withdraw(amount);
Thread.sleep(DELAY);
}
}
catch (InterruptedException exception)
{
}
}
}
And my main method class where I construct my Thread objects and such:
/**
* this program runs threads that deposit and withdraw money from the same bank account
*/
public class BankAccountThreadRunner
{
public static void main(String[] args)
{
BankAccount account = new BankAccount();
final double AMOUNT = 10000;
final int REPETITIONS = 10;
final int DEPOSIT_THREADS = 10;
final int WITHDRAW_THREADS = 2;
for (int i = 0; i < DEPOSIT_THREADS; i++)
{
DepositRunnable deposits =
new DepositRunnable(account, AMOUNT, REPETITIONS);
Thread depositThread = new Thread(deposits);
depositThread.run();
}
for (int i = 0; i < WITHDRAW_THREADS; i++)
{
WithdrawRunnable withdrawals =
new WithdrawRunnable(account, AMOUNT, REPETITIONS);
Thread withdrawThread = new Thread(withdrawals);
withdrawThread.run();
}
}
}
You are only using one thread. At no point does your code start or create any additional threads. You create
Runnableobjects, but then you never launch any threads but instead call theirrunmethods from the main thread!You should never call a
Runnableobject’srun()method (unless you actually want to run the code in the calling thread). See this tutorial for more information.