3.1 A Banking Example
As an application designer for a major bank, we are assigned to the development team for the
automated teller machine (ATM). As our first assignment, we are given the task of designing and
implementing the routine that allows a user to withdraw cash from the ATM. A first and simple
attempt at an algorithm may be as follows (see Figure 3.1 for the flow chart):
1. Check to make sure that the user has enough cash in the bank account to allow the withdrawal
to occur. If the user does not, then go to step 4.
2. Subtract the amount withdrawn from the user's account.
3. Dispense the cash from the teller machine to the user.
4. Print a receipt for the user.
Given this very simple algorithm, an implementation may be as follows:
public class
AutomatedTellerMachine extends Teller {
public void withdraw(float amount) {
Account a = getAccount();
if (a.deduct(amount))
dispense(amount);
printReceipt();
}
}
public class Account {
private float total;
public boolean deduct(float t) {
if (t <= total) {
total -= t;
return true;
}
return false;
}
}
As it turns out, it is possible for two people to have access to the same account (e.g., a joint account).
One day, a husband and wife both decide to empty the same account, and purely by chance, they
empty the account at the same time. We now have a race condition: if the two users withdraw from the
bank at the same time, causing the methods to be called at the same time, it is possible for the two
ATMs to confirm that the account has enough cash and dispense it to both parties. In effect, the two
users are causing two threads to access the account database at the same time.
There is a race condition because the action of checking the account and changing the account status
is not atomic. Here we have the husband thread and the wife thread competing for the account:
1. The husband thread begins to execute the deduct() method.
2. The husband thread confirms that the amount to deduct is less than or equal to the total in the
account.
3. The wife thread begins to execute the deduct() method.
4. The wife thread confirms that the amount to deduct is less than or equal to the total in the
account.
5. The wife thread performs the subtraction statement to deduct the amount, returns true, and
the ATM dispenses her cash.
6. The husband thread performs the subtraction statement to deduct the amount, returns true,
and the ATM dispenses his cash.
The Java specification provides certain mechanisms that deal specifically with this problem. The Java
language provides the synchronized keyword; in comparison with other threading systems, this
keyword allows the programmer access to a resource that is very similar to a mutex lock. For our
purposes, it simply prevents two or more threads from calling our deduct() method at the same time:
public class Account {
private float total;
public synchronized boolean deduct(float t) {
if (t <= total) {
total -= t;
return true;
}
return false;
}
}
By declaring the method as synchronized, if two users decide to withdraw cash from the ATM at the
same time, the first user executes the deduct() method while the second user waits until the first user
completes the deduct() method. Since only one user may execute the deduct() method at a time, the
race condition is eliminated.