java - 当两个条件对象分配给锁定对象时发生死锁

标签 java multithreading locking deadlock conditional-statements

由于某种原因,当我将两个条件对象分配给我的锁定对象时,我的程序死锁。当我注释掉条件对象之一时,它不会死锁。在将多个条件对象分配给单个锁定对象时,我是否遗漏了什么?下面是我的完整代码,以防您想完整地查看它。非常感谢您提前提供的所有帮助和时间!

重点关注我的 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();
                    }
                }
            }

最佳答案

您仅使用一个线程。您的代码绝不会启动或创建任何其他线程。您创建了 Runnable 对象,但是您永远不会启动任何线程,而是从主线程调用它们的 run 方法!

您永远不应该调用 Runnable 对象的 run() 方法(除非您确实想在调用线程中运行代码)。请参阅this tutorial了解更多信息。

关于java - 当两个条件对象分配给锁定对象时发生死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13695854/

相关文章:

java - ANTLR - 如何确定什么样的解析树 "best fits"一些代码

mysql - mysql 是否在选择、更新或删除时锁定表?

java - maven:包括单个 jar 的选定依赖项

java - 3DES (DESede) - 在 C# 中解密加密文本(由 JAVA 完成)

c++ - 适当删除QThread

vb.net - 委托(delegate)如何解决跨线程问题?

java - 服务无法正常工作

c# - SignalAndWait用于锁定上下文

sql-server - HOLDLOCK 对 UPDLOCK 有什么影响?

java - 如何从数据库访问所有用户?