我有一些模拟银行转帐的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
答案 0 :(得分:4)
try {
Thread.sleep(60);
} catch (InterruptedException e) {
e.printStackTrace();
}
这并不保证所有线程都已完成
而是将所有线程保留在列表中并在所有线程上调用连接
try {
for(Thread thr:threads)thr.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
答案 1 :(得分:1)
如果不同步openTransfers.add语句,两个线程可以同时将对象添加到openTransfers列表中。假设列表为空,两个线程都可以将元素添加到第一个位置(第二个线程覆盖第一个位置),然后两个都增加大小。这将为您提供一个包含1个对象和1个空指针的大小为2的列表。
这只是可能发生的许多不正确的事情之一。如果10个线程都执行size = size + 1
,则在完成size
之后可以是1到10之间的任何值。这可以解释为什么有时会有99个传输。 size
为99,现在并不意味着有99个项目,列表中可能有100个元素,或者98个,或者只有1个。
你真的应该尝试同步多个线程可以写入相同数据的所有内容。但要注意不要陷入僵局。