何らかの理由で、両方の条件オブジェクトをロック オブジェクトに割り当てると、プログラムがデッドロックします。条件オブジェクトの 1 つをコメントアウトすると、デッドロックになりません。複数の条件オブジェクトを 1 つのロック オブジェクトに割り当てる際に、私が見逃しているものはありますか? 全体を見たい場合に備えて、私のコード全体を以下に示します。事前にご協力いただき、ありがとうございました。
ロックおよび条件オブジェクトをインスタンス フィールドとして含む BankAccount クラスに注目します。
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;
}
}
私の実行可能なオブジェクト:
/**
* 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)
{
}
}
}
そして、Thread オブジェクトなどを構築するメイン メソッド クラス:
/**
* 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();
}
}
}