使用相同资源的Java非同步线程

使用相同资源的Java非同步线程,java,multithreading,Java,Multithreading,我必须制作一个非常简化的联合银行账户程序(在本例中,有3个用户都可以访问银行账户资源),但是我在正确使用Java线程时遇到了问题 以下是该程序应该如何工作。有些“用户”都可以使用任意设置的初始余额(我使用5000)访问一个联合银行帐户。他们可以在一次程序运行中三次提取或存款(无论每次提取或存款是随机生成的) 他们存款或取款的金额也是随机生成的,唯一的规则是金额不能超过当前余额的1/3 最后,在每个事务之后,当前线程必须“等待”1到10之间的随机秒数 现在是令人困惑的部分。我们的老师要求我们制作一

我必须制作一个非常简化的联合银行账户程序(在本例中,有3个用户都可以访问银行账户资源),但是我在正确使用Java线程时遇到了问题

以下是该程序应该如何工作。有些“用户”都可以使用任意设置的初始余额(我使用5000)访问一个联合银行帐户。他们可以在一次程序运行中三次提取或存款(无论每次提取或存款是随机生成的)

他们存款或取款的金额也是随机生成的,唯一的规则是金额不能超过当前余额的1/3

最后,在每个事务之后,当前线程必须“等待”1到10之间的随机秒数

现在是令人困惑的部分。我们的老师要求我们制作一个独特的NotEnoughBalance例外类,以防其中一个用户以某种方式提取的钱比当前账户中的钱多(但这是我的第一个困惑点:理论上,由于1/3规则,这永远不会发生)

以下是张贴在pastebin上的完整代码:

当前,当我运行main时:

public class BankAccount{
    public static void main(String[] args) throws InterruptedException{

        int capital = 5000;
        JointBankAccount acc = new JointBankAccount(capital);

        Thread t1 = new Thread(new Owner("Josh", acc));

        Thread t2 = new Thread(new Owner("Wade", acc));

        Thread t3 = new Thread(new Owner("Ben", acc));

        System.out.println(capital);
        String tname = Thread.currentThread().getName();
        System.out.println(tname);

        t1.start();
        t2.start();
        t3.start();

        t1.join();
        t2.join();
        t3.join();      

        for(AccountTransaction s : acc.history){
            System.out.println(s.toString());
        }
        System.out.println(acc.getBalance());
    }

}
我有时会在System.out.println(s.toString())上随机得到一个NPE异常

这是完全可以修复的,如果我使存款和取款功能同步

问题是,不知何故,我认为让它们同步违背了我们老师要求的目的。如果我让它们同步,那么我感觉我在确保每次提款都能成功地遵循1/3规则,而且余额不足的例外情况永远不会存在

当我删除synchronized时,我得到了NPE,这一事实也让我认为,可能是我没有正确地处理异常(当异常发生时)。我不知道


任何帮助都将不胜感激。

在我看来,这是理解原子事务的一个很好的练习

但是首先,NPE:one
JointBankAccount
实例在多个线程之间共享,因此
JointBankAccount
中包含的任何内容都像
历史
列表一样。
history
列表的类型为
ArrayList
,它不是线程安全的,即如果两个线程同时调用
add
方法,列表将中断。这很容易解决:
List。在更新余额之前,请使用读取锁读取最新余额,并应用任何规则确定是否可以更新余额。这允许您通知“所有者”,余额可能会被更新。但由于使用了读锁,您无法确定:余额可能已经更新。现在使用写锁并再次应用规则。这一次,您可以确定平衡值(它只能由具有单个写锁的代码更新),并且您可能会发现平衡不好(其中一个规则失败)。这就是
NotEnoughBalanceException
发挥作用的地方:您向“所有者”承诺余额可以更新,但现在您拥有了最终写入锁,您发现余额无法更新(原子事务无法完成)


这遵循一种非常常见的模式:使用“廉价”锁来确定事务是否可以完成(执行预检查),然后使用“昂贵”锁来执行事务,但始终假设事务可能失败,并在适当时重试事务。

如果您没有同步任何事务,那么就没有原子性或可见性保证了。你几乎肯定有比赛的危险。有时有些东西是永远不会扔出去的。有人看到过运行此程序时抛出的
内部错误
未知错误
吗?No@user1966576我的意思是,正确同步,将
noteNougbalanceException
添加到您的代码中,但不要抛出它(即,当
false==true
时抛出它)。如果我更改规则,以便在开始时保留5000资本,但提取或存入的金额可以是3000之间的随机数(因此不再有1/3规则)然后错误正确发生并被抛出。我刚试过。我想我的老师可能把作业给错了。这就像他希望发生比赛危险,但如果没有存款和取款同步,则该计划毫无意义,这使得比赛危险永远不会发生(根据1/3规则)。所以idk。