...
Unlike the previous compliant solution, this solution incurs no performance penalty, as multiple transfers can occur concurrently as long as the transfers involve distinct target accounts.
Compliant Solution (ReentrantLock)
In this compliant solution, each BankAccount
has a java.util.concurrent.locks.ReentrantLock
associated with it. This permits the depositAllAmount()
method to try acquiring both accounts' locks, but releasing its locks if it fails, and trying again later.
Code Block | ||
---|---|---|
| ||
class BankAccount {
private int balanceAmount; // Total amount in bank account
private final Lock lock = new ReentrantLock();
Lock getLock() {return lock;}
private static final int TIME = 1000; // ms
private BankAccount(int balance) {
this.balanceAmount = balance;
}
// Deposits the amount from this object instance to BankAccount instance argument ba
private void depositAllAmount(BankAccount ba) {
while (true) {
if (this.lock.tryLock()) {
try {
if (ba.lock.tryLock()) {
try {
ba.balanceAmount += this.balanceAmount;
this.balanceAmount = 0; // withdraw all amount from this instance
ba.displayAllAmount(); // Display the new balanceAmount in ba (may cause deadlock)
break;
} finally {
ba.getLock().unlock();
}
}
} finally {
this.getLock().unlock();
}
}
sleep( TIME);
}
}
private void displayAllAmount() {
while (true) {
if (lock.tryLock()) {
try {
System.out.println(balanceAmount);
break;
} finally {
lock.unlock();
}
}
sleep( TIME);
}
}
public static void initiateTransfer(final BankAccount first, final BankAccount second) {
Thread t = new Thread(new Runnable() {
public void run() {
first.depositAllAmount(second);
}
});
t.start();
}
}
|
Deadlock is impossible in this code, becase no routine grabs a lock and holds it indefinitely. If a lock is acquired, but the system cannot proceed immediately, it releases the lock and sleeps before trying the lock again.
Code that uses this lock behaves similar to synchronized code that uses the traditional monitor lock. ReentrantLock
provides several other capabilities, for instance, the tryLock() method does not block waiting if another thread is already holding the lock. The class java.util.concurrent.locks.ReentrantReadWriteLock
can be used when some thread requires a lock to write information while other threads require the lock to concurrently read the information.
Noncompliant Code Example
...