Page 247 - 6571
P. 247
Захист блоку коду засобами класу ReentrantLock в за-
гальному випадку виглядає наступним чином:
private Lock bankLock = new ReentrantLock();
public void transfer(){
try {
bankLock.lock();
// критична секція коду
} finally {
// зняти блокування, навіть у випадку генерації
винятку
bankLock.unlock();
}
}
Дана конструкція гарантує, що тільки один потік в конкрет-
ний момент часу зможе увійти в критичну секцію коду. Як тільки
потік заблокує об’єкт блокування, то жоден інший потік не зможе
виконати виклик методу lock() оскільки під час спроби це зро-
бити вони будуть дезактивовані доти, поки перший потік не зніме
блокування з об’єкта блокування. Також, дуже важливо
розмістити виклик методу unlock() у блоці finally, оскільки
блокування має бути знято навіть у випадку, якщо під час вико-
нання коду з критичної секції буде згенеровано виняток. В
іншому випадку інші потоки залишаться заблокованими назав-
жди.
Проте, потрібно мати на увазі, що у кожного об’єкта типу
Bank є свій власний об’єкт типу ReentrantLock. Якщо два по-
токи спробують звернутися до одного і того ж об’єкту типу
Bank, то один із них буде заблоковано. Але якщо два потоки
звертаються до різних об’єктів типу Bank, то кожен із них
отримає своє блокування і жоден з потоків при цьому не буде за-
блокованим, оскільки кожен із них працює з своїм екземпляром
класу Bank.
Описаний вище вид блокування називається реентерабель-
ним, оскільки потік може повторно захоплювати блокування,
яким він уже володіє. Для кожного блокування передбачений
лічильник захоплень, що відслідковує вкладені виклики методу
lock().
246