代码之家  ›  专栏  ›  技术社区  ›  Daniel Honig

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

  •  6
  • Daniel Honig  · 技术社区  · 15 年前

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

    AccountService定义为

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

    根据这个定义,实现transfer()的最佳方法是什么,这样您就可以保证transfer是一个原子操作。

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

    5 回复  |  直到 15 年前
        1
  •  11
  •   Edward Dale    15 年前

    在两者上同步 Account 帐户 s机具 Comparable ,对两个帐户进行排序,然后按顺序进行同步。

    如果不对帐户进行排序,那么如果一个线程从A转移到B,另一个线程从B转移到A,就有可能出现死锁。

    本示例将在第207页(共页)中讨论 Java Concurrency in Practice ,对于任何从事多线程Java开发的人来说都是一本非常重要的书。示例代码可从 publisher's website :

        2
  •  3
  •   Anton    15 年前
        3
  •  2
  •   Roman    15 年前

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

    解决问题的难度几乎不取决于您所处的环境。请详细描述您的系统,我们将尽力帮助您(什么样的应用程序?它使用web服务器吗?哪个web服务器?什么用于存储数据?以此类推)

        4
  •  1
  •   mikera    15 年前

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

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

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

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

        5
  •  0
  •   Pete    15 年前

    你不能避免使用 AtomicReference<Double> 账户余额,以及 get() set()