If you have a very unusual and special need that I cannot understand, it seems to me that your goal should be to protect the account balance from being damaged by several flows trying to credit or debit the account at the same time.
The way to do this would be as follows:
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; } } }
If your goal during a money transfer is to always ensure that both credit and debit actions occur as a single transaction or atomically, then using synchronization is not suitable. Even in a synchronized block, if an exception occurs, you lose the guarantee that both actions will occur atomically.
Implementing the transactions themselves is a very complex topic, so we usually use databases for this.
EDIT : OP asked: What is the difference between my example (one synchronized block multiplex) and your synchronized in the Account class?
This is a fair question. There are several differences. But I would say that the main difference is that, paradoxically, your example over -syncs. In other words, even though you are now using one synchronized block, your performance will actually be much worse, perhaps.
Consider the following example: You have 4 different bank accounts: give them the name A, B, C, D. And now you have 2 money transfers that are initiated at the same time:
- Transfer money from account A to account B.
- Transfer money from account C to account D.
I think that you will agree that since 2 money transfers occur on completely different accounts, there should be no harm (without the risk of corruption) when you execute both money transfers at the same time, right?
However, in your example, money transfers can only be done one after another. With mine, both money transfers occur simultaneously, but also safely. I will only block if both money transfers try to βtouchβ the same accounts.
Now imagine if you use this code to process hundreds, thousands or more of simultaneous money transfers. Then there is no doubt that my example will perform A LOT better than yours, while maintaining thread safety and protecting the account balance.
Essentially, my version of the code conceptually behaves much more like your original 2-synchronous block code. Except for the following enhancements:
- Potential deadlock scenario fixed.
- The intention is clearer.
- Provides better encapsulation. (This means that even if some other code outside the
transferMoney method should have tried to debit or credit some amounts, I would still keep the flows safe, and you wouldnβt. I know that you said that itβs not yours case, but with my version, the design absolutely guarantees this)