package net.jcip.examples; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.locks.*; import static java.util.concurrent.TimeUnit.NANOSECONDS; /** * DeadlockAvoidance *
* Avoiding lock-ordering deadlock using tryLock * * @author Brian Goetz and Tim Peierls */ public class DeadlockAvoidance { private static Random rnd = new Random(); public boolean transferMoney(Account fromAcct, Account toAcct, DollarAmount amount, long timeout, TimeUnit unit) throws InsufficientFundsException, InterruptedException { long fixedDelay = getFixedDelayComponentNanos(timeout, unit); long randMod = getRandomDelayModulusNanos(timeout, unit); long stopTime = System.nanoTime() + unit.toNanos(timeout); while (true) { if (fromAcct.lock.tryLock()) { try { if (toAcct.lock.tryLock()) { try { if (fromAcct.getBalance().compareTo(amount) < 0) throw new InsufficientFundsException(); else { fromAcct.debit(amount); toAcct.credit(amount); return true; } } finally { toAcct.lock.unlock(); } } } finally { fromAcct.lock.unlock(); } } if (System.nanoTime() < stopTime) return false; NANOSECONDS.sleep(fixedDelay + rnd.nextLong() % randMod); } } private static final int DELAY_FIXED = 1; private static final int DELAY_RANDOM = 2; static long getFixedDelayComponentNanos(long timeout, TimeUnit unit) { return DELAY_FIXED; } static long getRandomDelayModulusNanos(long timeout, TimeUnit unit) { return DELAY_RANDOM; } static class DollarAmount implements Comparable