Вот пример такого лока, код, который, казалось бы, работает верно, но может привести к дедлоку, если 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. В коде выше например можно добавить проверку, которая определяет удалось ли нам осуществить операцию, при необходимости повторить её снова.
Комментариев нет:
Отправить комментарий