繁体   English   中英

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

[英]Java Nonsynchronized threads using the same resource

我必须制作一个非常简化的联合银行账户计划(在这个例子中有3个用户都可以访问银行账户资源),但我无法正确使用Java线程。

这是程序应该如何工作。 有“用户”都可以访问一个具有任意设置初始余额的联合银行账户(我用了5000)。 他们每人可以在一次运行程序中三次取款或存款(无论是每次随机抽取还是存款)。

他们存入或取出的金额也是随机生成的,唯一的规则是金额永远不会超过当前余额的1/3。

在每次交易之后,当前线程必须在1到10之间“等待”一个随机的秒数。

现在这里是令人困惑的部分。 我们的老师要求我们制作一个独特的NotEnoughBalance异常类,以防其中一个用户以某种方式提取比目前帐户中更多的钱(但这是我的第一个混淆点:理论上这可能永远不会发生,因为1/3规则)。

这是在pastebin上发布的完整代码:

http://pastebin.com/Upam56NF

目前,当我运行主要:

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规则,并且不能存在足够的Balance异常。

当我删除synchronized时,我得到NPE的事实也让我想到可能错误在于我没有在它发生时正确处理异常。 我不知道。

任何帮助将不胜感激。

这对我来说就像理解原子事务一样很好。

但首先是NPE:一个JointBankAccount实例在多个线程之间共享,因此JointBankAccount包含的任何内容JointBankAccounthistory列表一样。 history列表的类型为ArrayList ,它不是线程安全的,即如果两个线程同时调用add方法,则列表会中断。 这很容易修复: List<AccountTransaction> history = Collections.synchronizedList(new ArrayList<AccountTransaction>());

现在进行原子交易。 由于任何线程都可以随时更改余额,因此当您读取余额时,余额已经过时。 即如下语句if (balance > 1000) then updateBalance()是无效的,因为平衡可能已经改变后then 避免这种情况的一种方法是同步所有内容(尽管如此,你必须要小心,例如使用AomticInteger注册余额)。 NotEnoughBalanceException意味着使用ReentrantReadWriteLock的不同工作方式。 在更新余额之前,请使用读锁来读取最新余额并应用任何规则以确定是否可以更新余额。 这允许您通知“所有者”可能更新余额。 但是,由于您使用了读锁定,因此无法确定:余额可能已经更新。 现在使用写锁并再次应用规则。 这次您可以确定平衡值(它只能由具有单个写锁定的代码更新),您可能会发现余额不好(其中一个规则失败)。 这是NotEnoughBalanceException发挥作用的地方:你承诺“所有者”可以更新余额,但现在你有最后的写锁定,你发现无法更新余额(原子事务无法完成)。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM