CSCE 314 Lecture 35

From Notes
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();
        }
    }
}