Page 181 - 6571
P. 181
// об’єкт класу ReentrantLock, реалізує інтерфейс L
ck
private Lock bankLock = new ReentrantLock();
...
public void transfer(int from, int to, int amount) {
bankLock.lock();
try {
System.out.print(Thread.currentThread());
accounts[from] = accounts[from] - amount;
System.out.printf("%10.2f з %d до %d", amount,
from, to);
accounts[to] = accounts[to] + amount;
System.out.printf("Загальний баланс: %10.2f%n",
getTotalBalance());
} finally {
bankLock.unlock();
}
}
}
Припустимо, що в одному із потоків викликається метод
transfer() і даний потік призупиняється під час його
виконання. Припустимо також, що в цей момент другий потік
також викликає метод transfer(), проте, він буде
дезактивований і змушений очікувати, поки виконання методу
transfer() не завершиться в першому потоці. І тільки тоді,
коли перший потік зніме блокування, другий потік зможе
продовжити своє виконання. Усе це дає змогу гарантувати, що
загальний баланс на рахунку в даному випадку буде завжди
залишатись сталим.
Проте, потрібно мати на увазі, що у кожного об’єкта типу
Bank є свій власний об’єкт типу ReentrantLock. Якщо два
потоки спробують звернутися до одного і того ж об’єкту типу
Bank, то один із них буде заблоковано. Але якщо два потоки
звертаються до різних об’єктів типу Bank, то кожен із них
отримає своє блокування і жоден з потоків при цьому не буде
заблокованим, оскільки кожен із них працює з своїм екземпляром
класу Bank.
Описаний вище вид блокування називається
реентерабельним, оскільки потік може повторно захоплювати
блокування, яким він уже володіє. Для кожного блокування
180