CSCE 314 Lecture 35
Jump to navigation
Jump to search
« previous | Monday, November 28, 2011 | next »
Race Conditions (cont'd)
public void deposit(double amount) {
balance += amount
}
The code above is not atomic and balance could be updated while the CPU is still computing the new balance.
One solution is to place a lock on the information:
public class BankAccount {
private Lock balanceChangeLock;
private double balance; // don't use 'double' in real life... that gets you fired!
public BankAccount() {
balanceChangeLock = new ReentrantLock();
}
public void deposit(double amount) {
balanceChangeLock.lock();
try { // this is called a "critical section"... try to make these as short as possible.
balance += amount
} finally {
balanceChangeLock.unlock();
}
}
}
Synchronization
Similar to locking within objects using a keyword:
public synchronized void deposit(double amount){ /* ... */ }
This wraps the entire function body in a lock-try-finally block.
Preventing overdraft
First attempt:
if (account.getBalance() >= amount) account.withdraw(amount);
something could update balance between test and withdraw.
Second attempt:
public void withdraw(double amount) {
balanceChangeLock.lock();
try {
while (balance < amount) {}
// wait for balance to grow, which never happens since balance is locked
balance -= amount;
} finally {
balanceChangeLock.unlock();
}
}
The example results in a deadlock. We can use a Condition object to temporarily release a lock.
public BankAccount {
private Lock balanceChangeLock;
private Condition sufficientFundsCondition;
public BankAccount() {
balance = 0;
balanceChangeLock = new ReentrantLock();
sufficientFundsCondition = balanceChangeLock.newCondition();
}
public void deposit(double amount) {
balanceChangeLock.lock();
try {
// ...
sufficientFundsCondition.signalAll();
} finally {
balanceChangeLock.unlock();
}
}
public void withdraw(double amount) {
balanceChangeLock.lock();
try {
while (balance < amount)
sufficientFundsCondition.await()
// ...
} finally {
balanceChangeLock.unlock();
}
}
}