Big*_*c66 1 java parallel-processing concurrency synchronization
可以说我有一个有两个方法的类calculateBonus(Account a)和calculatePenalty(Account a).
假设我将synchronized关键字添加到方法中或synchronized(this)在方法内部有一个块.这是否有效地意味着如果一个线程正在计算账户上的奖金,那么在奖金完成之前,其他线程是否可以计算其他账户的罚款?
处罚和奖金是多种多样和复杂的,账户可能同时收到.它们的计算顺序无关紧要(有一个截止日期,因此不会影响另一个的结果)但是我不会尝试同时在同一个帐户上计算两者,这一点至关重要(对于明显的数据)一致性原因,每个方法内部都有状态和审计跟踪信息更新.
设计我的代码的最佳方法是什么,以便我可以安全地最大化并行处理?
到目前为止我考虑过这些选项:
1)将计算奖金和罚金的代码放在不同的类中,并使用synchronized方法上的关键字.不喜欢这个想法,因为我希望将一些共享的复杂函数放在一起,它们不受IO限制并快速执行,因此不会影响性能.
2)同步传入的Account参数.如果我正确理解这意味着我无法计算在另一个线程中执行的另一个账户的奖金,直到在第一个线程中的第一个账户上计算奖金.但我可以计算在不同的线程在不同的帐户罚款-只是不相同的帐户.我最喜欢这个,但我想确保我理解正确.
3)为我想要同步的每个方法创建一个内部私有锁对象,一个用于奖励,另一个用于惩罚.如果正确理解这意味着只有一个线程可以一次计算奖金,但它不会阻止另一个线程同时计算同一账户的罚款.
现在我明白我必须小心避免死锁,我计划确保任何同步块内的任何内容都不依赖于对其他同步方法的调用.我还打算确保在计算中使用的影响最终值的任何局部变量都在synchronized块内.
我认为选项2 - 或其中的变体 - 是你最好的选择,但我认为你仍然会稍微误解它:
在传入的Account参数上同步.如果我正确理解这意味着我无法计算在另一个线程中执行的另一个账户的奖金,直到在第一个线程中的第一个账户上计算奖金.
不 - 这意味着:
现在我通常不喜欢锁定任何公开可见的引用(例如Account参数),因为它使得更难以推断锁定.通常优选的是,每个Account实例具有仅用于锁定的其自己的对象,例如
private final Object lock = new Object();
Run Code Online (Sandbox Code Playgroud)
以及例如Account锁定它的方法......但如果你不能把方法放进去Account,你就不能真的这样做.也许这些方法应该在Account吗?也许你应该改变的责任-让您拥有Account.calculateBonus(BonusFormula)和Account.calculatePenalty(PenaltyFormula)或类似的东西?
在不知道更多细节的情况下很难确定,但通常感觉锁只应该只对执行同步的对象知道.