gpt4 book ai didi

java - 嵌套同步块(synchronized block)

转载 作者:塔克拉玛干 更新时间:2023-11-03 05:09:04 34 4
gpt4 key购买 nike

假设我有下一节课:

public class Service {
public void transferMoney(Account fromAcct, Account toAcct, int amount) {
synchronized (fromAcct) {
synchronized (toAccount) { // could we use here only one synchronized block?
fromAcct.credit(amount);
toAccount.debit(amount);
}
}
}
}

class Account {
private int amount = 0;

public void credit(int sum) {
amount = amount + sum;
}

public void debit(int sum) {
amount = amount - sum;
}
}

例如,我知道我们只能在 transferMoney 方法中更改 fromAccttoAcct 对象的状态。那么我们可以用一个同步 block 重写我们的方法吗?

public class Service {
private final Object mux = new Object();

public void transferMoney(Account fromAcct, Account toAcct, int amount) {
synchronized(mux) {
fromAcct.credit(amount);
toAcct.debit(amount);
}
}
}

最佳答案

除非您有我无法理解的非常不寻常和特殊的需求,否则在我看来,您的目标应该是保护帐户余额不被多个线程同时尝试贷记或借记帐户破坏.

这样做的方法是这样的:

public class Service {
public void transferMoney(Account fromAcct, Account toAcct, int amount) {
fromAcct.credit(amount);
toAccount.debit(amount);
}
}

class Account {
private final object syncObject = new Object();
private int amount = 0;

public void credit(int sum) {
synchronized(syncObject) {
amount = amount + sum;
}
}

public void debit(int sum) {
synchronized(syncObject) {
amount = amount - sum;
}
}
}

如果您在汇款过程中的目标是始终确保贷方和借方操作作为一个事务发生,或者以原子方式发生,那么使用同步不是正确的方法。即使在同步块(synchronized block)中,如果发生异常,您也无法保证这两个操作将自动发生。

自己实现交易是一个非常复杂的话题,这就是为什么我们通常使用数据库来为我们做这件事。

编辑:OP 问:我的示例(一个同步块(synchronized block) mux)和您在 Account 类中同步的示例有什么区别?

这是一个公平的问题。有一些差异。但我要说的是,主要区别在于,具有讽刺意味的是,您的示例过度-同步。换句话说,即使您现在使用单个同步块(synchronized block),您的性能实际上可能会更差。

考虑以下示例:您有 4 个不同的银行账户:我们将它们命名为 A、B、C、D。现在您有 2 笔同时发起的汇款:

  1. 从账户 A 向账户 B 转账。
  2. 从账户 C 向账户 D 转账。

我认为您会同意,因为两笔汇款是在完全独立的账户上进行的,所以同时执行两笔汇款应该没有危害(没有腐败风险),对吗?

但是,对于您的示例,汇款只能一个接一个地执行。在我的情况下,两种汇款同时发生,但也很安全。只有当两次汇款都试图“触及”相同的账户时,我才会阻止。

现在想象一下,如果您使用此代码处理数百、数千或更多的并发汇款。那么毫无疑问,我的示例将比您的示例执行得更好,同时仍然保持线程安全,并保护帐户余额的正确性。

实际上,我的代码版本在概念上表现得更像您原来的 2 同步块(synchronized block)代码。除了以下改进:

  • 修复了潜在的死锁情况。
  • 意图更清晰。
  • 提供更好的封装。 (这意味着即使 transferMoney 方法之外的一些其他代码尝试借记或贷记一些金额,我仍然会保持线程安全,而你不会。我知道你说过这不是你的案例,但对于我的版本,设计绝对保证)

关于java - 嵌套同步块(synchronized block),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30632329/

34 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com