出于某种原因,当我将两个条件对象分配给我的锁定对象时,我的程序死锁。当我注释掉其中一个条件对象时,它不会死锁。在将多个条件对象分配给单个锁定对象时,是否有一些我缺少的东西?以下是我的全部代码,以防您希望完整地查看它。非常感谢你提前给予的帮助和时间!
关注我的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;
}
}
My Runnable对象:
/**
* 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();
}
}
}
答案 0 :(得分:4)
您只使用一个帖子。您的代码在任何时候都不会启动或创建任何其他线程。你创建了Runnable
个对象,但是你永远不会启动任何线程,而是从主线程中调用它们的run
方法!
你永远不应该调用Runnable
对象的run()
方法(除非你真的想在调用线程中运行代码)。有关详细信息,请参阅this tutorial。
答案 1 :(得分:1)
只有当两个资源可以被“锁定”以进行独占访问时才会出现死锁(我称之为“锁定”,尽管它们可能是任何此类资源),但是使用模式如下:
A
打算获取锁X
,然后Y
B
打算获取锁Y
,然后X
如果流程A
获得了锁定X
而流程B
获得了锁定Y
,那么您将陷入僵局。
这是你(必须)在这里发生的一个版本。
答案 2 :(得分:0)
事实是,无论何时允许线程一次锁定多个资源并且不采取任何预防措施(并且实际上存在多线程),死锁是可能的(并且几乎肯定会发生)最终)。
处理死锁基本上有两种选择:
使用死锁跟踪机制可以在简单的情况下完成检测死锁,其中,当线程等待锁时,它会检查线程所持有的锁,它正在等待查看是否有任何(直接或间接)引导回到当前的主题。
也可以使用超时机制检测死锁,但此方案通常无法区分死锁和长时间运行。
在任何一种情况下,当检测到死锁时,一个或多个线程被迫放弃部分或全部锁定(这可能需要某种“回滚”机制来进行部分更改)。
最简单的“优先级”方案是一次只允许一个锁。稍微复杂一点的是要求立即获取所有锁。真正的优先级方案为不同的类别分配不同的可锁定资源,然后以“优先级顺序”对类别进行“排序”,这样如果您已经在类别N或类别中保留任何锁定,则无法获取类别N上的任何锁定; Ñ
但是,遗憾的是,任何方案(除了可能的基本超时方案)都可以通过与消息通信并等待来自其他线程的消息的线程撤消。如果你考虑一下,这在概念上与等待获得另一个线程的锁定相同。