I am trying to understand the concept of synchronizing on an object. Using this example from the Java Cert Book, can you help me understand the difference in behavior between the following 2 pieces of code (one where we synchronize on the object whose methods/operations we want to protect from the race condition and another where we use a helper object as a lock to achieve the same goal):
1.
class Client {
BankAccount account;
public void updateTransaction() {
synchronized (account) {
account.update(); // update is safe because of lock on account obj
}
}
public double withdrawFunds() {
double amt;
synchronized (account) {
account.calculateInterest();
amt= account.withdraw();
}
return amt;
}
}
2.
class Client {
BankAccount account;
Object lock = new Object();
public void updateTransaction() {
synchronized (lock) {
account.update(); // update is safe because of a lock
}
}
public double withdrawFunds() {
double amt;
synchronized (lock) {
account.calculateInterest();
amt= account.withdraw();
}
return amt;
}
}
The difference is with respect to what other threads are doing in your system. In the first case, if there are any reasons why some other logic (defined in some other code) should not be exercised concurrently with the updateTransaction method, that logic could also be synchronized on the account object. Conversely, you might have a false synchronization if some unrelated code also uses account as the lock when it has nothing to do with updateTransaction.
In the second case, the lock object is only visible to the Client class, so you are guaranteed that the only synchronization that goes on is what you have specified in this class.
I agree with Peter Lawrey that the best approach is to encapsulate the synchronization logic in a single place where it makes sense, and use private/protected visibility lock objects for that.