Page 149 - 4868
P. 149
147 Ошибка! Стиль не определен.
Коли потік входить у блок позначений словом synchronized, то він
захоплює блокування об’єкта obj.
synchronized (obj) { // синтаксис синхронізованого блоку
критична секція коду;
}
Іноді в коді зустрічаються спеціальні блокування схожі до наступного:
public class Bank {
private double[] accounts;
private Object lock = new Object();
...
public void transfer(int from, int to, int amount) {
synchronized (lock) { // спеціальне блокування
accounts[from] = accounts[from] - amount;
accounts[to] = accounts[to] + amount;
}
System.out.println();
}
}
В даному випадку об’єкт lock створюється тільки для використання
вбудованого блокування, яке є у кожного об’єкта в мові Java. Вбудованим
блокуванням об’єкта іноді користуються для реалізації додаткових
атомарних операцій. Така практика отримала назву клієнтського блокування.
Розглянемо як приклад клас Vector, методи якого є синхронізованими. А
тепер припустимо, що залишки на банківських рахунках зберігаються в
об’єкті типу Vector<Double>. Нижче наведена наївна реалізація методу
transfer().
public void transfer(Vector<Double> accounts, int from,
int to, int amount) { // помилка!
accounts.set(from, accounts.get(from) - amount);
accounts.set(to, accounts.get(to) + amount);
System.out.println();
}
Методи get() та set() визначені в класі Vector є синхронізованими,
проте, цілком можливо, що потік буде призупинений на методі transfer()
після завершення першого виклику методу get(). Інший потік зможе
записати будь-яке інше значення на ту ж саму позицію. Тому, для захоплення
блокування можна використати наступний підхід:
public void transfer(Vector<Double> accounts, int from,
int to, int amount) {
synchronized (accounts) {
accounts.set(from, accounts.get(from) - amount);
accounts.set(to, accounts.get(to) + amount);
}