为什么线程仍然不一致?

我有一些模拟银行转账的java代码。 帐户类只有一个余额字段和一个向余额字段添加一些余额的转移方法。

TransferManager定义了一个Transfer类,它使用两个Account对象将一个帐户中的给定金额转移到另一个帐户作为参数传递。

Manager本身有两个需要同步的重要方法,因为它们都在同一个资源上运行,并且它们将以线程方式调用:

public synchronized void issueTransfer(Account from, Account to, int amount) { openTransfers.add(new Transfer(from, to, amount)); issuedTransfers++; } public synchronized void performTransfers() { for(Transfer transaction : openTransfers) { transaction.performTransfer(); performedTransfers++; } openTransfers.clear(); } 

如果没有同步语句,我会在存储和读取传输的arraylist上获得NullPointerExceptions。

BankTest产生10个线程,每个线程发出10次传输。 看看BankTest.java吧。 问题是并不总是发出10 * 10次转账。 有时有98或99:

在此处输入图像描述

我是否必须向BankTest.java添加同步? 我该怎么办? 还有其他想法或建议吗?

TransferManager.java:http://pastebin.com/Je4ExhUz

BankTest.java:http://pastebin.com/cdpWhHPb

Exersice3.java:http://pastebin.com/v7pwJ5T1

Account.java:http://pastebin.com/QYEeWy5Z

 try { Thread.sleep(60); } catch (InterruptedException e) { e.printStackTrace(); } 

这并不能保证所有线程都完成

而是将所有线程保留在列表中,并在所有线程上调用join

 try { for(Thread thr:threads)thr.join(); } catch (InterruptedException e) { e.printStackTrace(); } 

比赛条件?

如果不同步openTransfers.add语句,两个线程可以同时将对象添加到openTransfers列表。 假设列表为空,两个线程都可以将元素添加到第一个位置(第二个线程覆盖第一个位置),然后两个都增加大小。 这将为您提供一个大小为2的列表,其中包含1个对象和1个空指针。

这只是可能发生的许多不正确的事情之一。 如果10个线程都执行size = size + 1 ,则在完成size可以是1到10之间的任何值。这可以解释为什么有时会有99个传输。 这个size是99,现在并不意味着有99个项目,列表中可能有100个元素,或98,或者只有1个。

你真的应该尝试同步多个线程可以写入相同数据的所有内容。 但要注意不要陷入僵局。