澄清同步

时间:2011-03-09 17:38:53

标签: java concurrency synchronization parallel-processing

假设我的课程有两种方法calculateBonus(Account a)calculatePenalty(Account a)

假设我将synchronized关键字添加到方法中,或者在方法中包含synchronized(this)块。这是否有效地意味着如果一个线程正在计算一个账户的奖金,那么在奖金完成之前,没有其他线程可以计算另一个账户的罚款?

处罚和奖金多种多样且复杂,账户可能同时收到。它们的计算顺序无关紧要(有一个截止日期,因此不会影响另一个的结果)但是我不会尝试同时在同一个帐户上计算两者,这一点至关重要(对于明显的数据)一致性原因,每种方法都有更新状态和审计跟踪信息。)

设计我的代码的最佳方法是什么,以便我可以安全地最大化并行处理?

到目前为止,我已考虑过这些选项:

1)将计算奖金和罚金的代码放在不同的类中,并使用方法上的synchronized关键字。不喜欢这个想法,因为我希望将一些共享的复杂函数放在一起,它们不受IO限制并快速执行,因此不会影响性能。

2)同步传入的Account参数。如果我正确理解这意味着我无法计算在另一个线程中执行的另一个账户的奖金,直到在第一个线程中的第一个账户上计算奖金。但我可以在不同的帖子中计算不同帐户的罚款 - 而不是相同的帐户。我最喜欢这个,但我想确保我理解正确。

3)为我想要同步的每个方法创建一个内部私有锁对象,一个用于奖励,另一个用于惩罚。如果正确理解这意味着只有一个线程可以一次计算奖金,但阻止另一个线程在同一个相同账户上计算罚款时间。

现在我明白我必须小心避免死锁,我计划确保任何同步块内的任何内容都不依赖于对其他同步方法的调用。我还打算确保计算中用于影响最终值的任何局部变量都在synchronized块内。

1 个答案:

答案 0 :(得分:6)

我认为选项2 - 或其中的变体 - 是你最好的选择,但我认为你仍然会稍微误解它:

  

同步传入的Account参数。如果我正确理解这意味着我无法计算在另一个线程中执行的另一个账户的奖金,直到在第一个线程中的第一个账户上计算奖金。

不 - 这意味着:

  • 您将无法在相同的帐户中计算奖励罚款,因为您的帖子正在为该帐户持有监视器。
  • 任何线程都可以在不同的帐户上计算奖金或罚款,因为这会有不同的监控。

现在我通常不喜欢锁定任何公开可见的引用(例如Account参数),因为它使得更难以推断锁定。通常最好每个Account实例都有自己的对象用于锁定,例如

private final Object lock = new Object();

并且例如Account中的方法可以锁定...但是如果你不能将方法放在Account中,那么你就无法真正做到这一点。也许这些方法应该Account中?也许你应该改变责任 - 这样你就有Account.calculateBonus(BonusFormula)Account.calculatePenalty(PenaltyFormula)或类似的东西?

在不知道更多详细信息的情况下很难肯定地说,但它通常感觉就像只有执行同步的对象才能知道锁。