Java Deadlock

Наиболее частая причина дед-локов - это порядок при котором потоки берут лок на объекты. Один поток берет лок на объект A и ждет, второго потока, который взял лок на объект B, который в свою очередь ждет, когда 1 поток отпустит объект A.

Вот пример такого лока, код, который, казалось бы, работает верно, но может привести к дедлоку, если from и to поменяются местами при следющем вызове.

	public void transerMoney(Account from, Account to, Dollar amount) {
		synchronized (from) {
			synchronized (to) {
				if (from.getBalance().compareTo(amount) < 0) {
					throw new InsufficientFundsException();
				}
				from.debit(amount);
				to.credit(amout);
			}
		}
	}
как можно переписать этот код ? ну например можно определять хеш объекта, чтоб установить порядок лока.
	public void transerMoney(Account from, Account to, Dollar amount) {
		int fromHash = System.identityHashCode(from);
		int toHash = System.identityHashCode(to);
		if (fromHash < toHash) {
			synchronized (from) {
				synchronized (to) {
					transfer();
				}
			}
		} else if (fromHash > toHash){
			synchronized (to) {
				synchronized (from) {
					transfer();
				}
			}						
		}
	}

Можно также использовать интерфейс Lock и явно создать ReentrantLock
	public void transerMoney(Account from, Account to, Dollar amount) {
		if (from.lock.tryLock()) {
			try {
				if (to.lock.tryLock()) {
					try {
						transfer();
					} finally {
						to.lock.unlock();
					}
				}
			} finally {
				from.lock.unlock();
			}
		}
	}

tryLock возьмет лок или сразу же вернет false, если он не может взять lock. В коде выше например можно добавить проверку, которая определяет удалось ли нам осуществить операцию, при необходимости повторить её снова.

Комментариев нет:

Отправить комментарий