为什么线程仍然不一致?

时间:2011-05-08 15:38:38

标签: java multithreading

我有一些模拟银行转帐的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:

enter image description here

我是否必须向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

2 个答案:

答案 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)

Race conditions?

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

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

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