编写在多线程Java环境中更新两个对象的方法的最佳方法?

时间:2010-06-02 14:25:47

标签: java multithreading parallel-processing java-5

假设我们有一个名为AccountService的类来管理帐户状态。

AccountService定义为

interface AccountService{
 public void debit(account);
 public void credit(account);
 public void transfer(Account account, Account account1);

}

鉴于此定义,实现transfer()的最佳方法是什么,以便您可以保证传输是原子操作。

我对引用Java 1.4代码的答案感兴趣,以及可能使用Java 5中java.util.concurrent资源的答案

5 个答案:

答案 0 :(得分:11)

同步两个Account个对象并进行传输。确保始终以相同的顺序同步。为此,请创建Account工具Comparable,对这两个帐户进行排序,然后按此顺序进行同步。

如果您没有订购帐户,如果一个线程从A转移到B而另一个从B转移到A,则会出现死锁的可能性。

这个确切的例子在Java Concurrency in Practice的第207页讨论,这是一本关于任何进行多线程Java开发的人的重要书籍。示例代码可从publisher's website

获得

答案 1 :(得分:3)

这里非常好地解释了一个经典的例子 - http://www.javaworld.com/javaworld/jw-10-2001/jw-1012-deadlock.html?page=4

答案 2 :(得分:2)

您可能需要获得完整的交易支持(如果它当然是真正的应用程序)。

解决方案的难度很大程度上取决于您的环境。详细描述您的系统,我们会尽力帮助您(什么样的应用程序?它使用Web服务器?哪个Web服务器?什么用于存储数据?等等)

答案 3 :(得分:1)

如果您可以保证所有访问都是通过传输方法进行的,那么最简单的方法可能就是使传输成为同步方法。这将是线程安全的,因为这可以保证在任何时候只有一个线程将运行传输方法。

如果其他方法也可以访问AccountService,那么您可能决定让它们都使用单个全局锁。一种简单的方法是在同步(X){...}块中包围访问AccountService的所有代码,其中X是一些共享/单一对象实例(可能是AccountService实例本身)。这将是线程安全的,因为任何时候只有一个线程将访问AccountService,即使它们使用不同的方法。

如果仍然不够,那么您将需要使用更复杂的锁定方法。一种常见的方法是在修改帐户之前单独锁定帐户...但是您必须非常小心地按照一致的顺序(例如通过帐户ID)来锁定帐户,否则您将遇到死锁。

最后,如果AccountService是一个远程服务,那么你将进入分布式锁定领域....除非你拥有计算机科学博士学位和多年的研究预算,否则应该避免去那里。

答案 4 :(得分:0)

您无法避免使用AtomicReference<Double>同步帐户余额以及get()set()吗?