6

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

AccountService 定义为

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

}

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

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

4

5 回答 5

11

在两个对象上同步Account并进行传输。确保始终以相同的顺序进行同步。为此,请让Accounts 实现Comparable,对两个帐户进行排序,并按该顺序进行同步。

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

这个确切的例子在Java Concurrency in Practice的第 207 页上进行了讨论,这本书对于任何从事多线程 Java 开发的人来说都是一本重要的书。示例代码可从发布者的网站获得:

于 2010-06-02T14:31:39.010 回答
3

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

于 2010-06-02T14:34:26.967 回答
2

您可能需要完整的事务支持(当然,如果它是一个真正的应用程序)。

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

于 2010-06-02T14:31:41.117 回答
1

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

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

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

最后,如果 AccountService 是一项远程服务,那么您将进入分布式锁定领域……除非您拥有计算机科学博士学位并且需要花费多年的研究预算,否则您可能应该避免去那里。

于 2010-06-02T14:50:16.157 回答
0

您不能避免使用 和 来同步帐户AtomicReference<Double>余额吗?get()set()

于 2010-06-02T14:42:05.540 回答