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);
                       }
   144   145   146   147   148   149   150   151   152   153   154