假设我们有一个名为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资源的答案
答案 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()
吗?