|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Page 4 of 4
Listing 4. Use an ordering to acquire locks in a fixed sequence
public void transferMoney(Account fromAccount,
Account toAccount,
DollarAmount amountToTransfer) {
Account firstLock, secondLock;
if (fromAccount.accountNumber() == toAccount.accountNumber())
throw new Exception("Cannot transfer from account to itself");
else if (fromAccount.accountNumber() < toAccount.accountNumber()) {
firstLock = fromAccount;
secondLock = toAccount;
}
else {
firstLock = toAccount;
secondLock = fromAccount;
}
synchronized (firstLock) {
synchronized (secondLock) {
if (fromAccount.hasSufficientBalance(amountToTransfer) {
fromAccount.debit(amountToTransfer);
toAccount.credit(amountToTransfer);
}
}
}
}
Now the order in which the accounts are specified in the call to transferMoney() doesn't matter; the locks are always acquired in the same order.
A critical -- but often overlooked -- element of any locking strategy is documentation. Unfortunately, even in cases where much care is taken to design a locking strategy, often much less effort is spent documenting it. If your program uses a small set of singleton locks, you should document your lock-ordering assumptions as clearly as possible so that future maintainers can meet the lock-ordering requirements. If a method must acquire a lock to perform its function or must be called with a specific lock held, the method's Javadoc should note that fact. That way, future developers will know that calling a given method might entail acquiring a lock.
Few programs or class libraries adequately document their locking use. At a minimum, every method should document the locks that it acquires and whether callers must hold a lock to call the method safely. In addition, classes should document whether or not, or under what conditions, they are thread safe.
Because deadlocks are often not obvious and occur infrequently and unpredictably, they can cause serious problems in Java programs. By paying attention to your program's locking behavior at design time and defining rules for when and how to acquire multiple locks, you can reduce the likelihood of deadlocks considerably. Remember to document your program's lock acquisition rules and its use of synchronization carefully; the time spent documenting simple locking assumptions will pay off by greatly reducing the chance of deadlock and other concurrency problems later.