Page 191 - 6571
P. 191

метод  wait()  зазвичай  перебуває  в  стані  очікування  до  того
            часу,  поки  не  буде  викликаний  метод  notify()  або
            notifyAll(),  проте  існує  ймовірність,  що  в  дуже  рідкісних

            випадках         призупинений            потік       може       бути       поновлений
            підробленим  сигналом.  Через  цю  малоймовірну  можливості
            Oracle рекомендує виконувати виклики методу wait() всередині

            циклу,  що  перевіряє  умову  очікування  потоку.  У  наведеному
            нижче прикладі продемонстровано саме такий підхід.

                  class Bank {
                    private double[] accounts;
                    public synchronized void transfer(int from, int to,
                                int amount) throws InterruptedException {
                      while (accounts[from] < amount)
                        wait(); // очікувати згідно умови
                      accounts[from] = accounts[from] - amount;
                      accounts[to] = accounts[to] + amount;
                      // повідомити всі потоки, що очікують згідно умови
                      notifyAll();
                    }
                    public synchronized double getTotalBalance() {...}
                  }

                  Метод wait() переводить потік в стан очікування, а методи

            notifyAll() / notify()  розблокують  призупинені  потоки.
            Виклик  методу  wait()  або  notifyAll()  рівнозначний

            наступному коду:
                  buildConditional.await();
                  buildConditional.signalAll();

                  Отже,  використання  ключового  слова  synchronized

            дозволяє  суттєво  скоротити  вихідний  код  програми.  В  даному
            випадку,  блокування  керує  потоками,  які  намагаються  увійти  в
            метод  synchronized,  а  умова  керує  потоками,  що  викликали

            метод wait().
                  Поля  та  змінні  типу  volatile.  Часто  для  захисту  одного
            або  двох  полів  класу  від  асинхронного  доступу  потрібно

            синхронізувати доступ до усього об’єкта, що є занадто затратною
            операцією  в  плані  розподілу  процесорного  часу.  Зрештою,  що
            може статися поганого під час асинхронних операцій запису або

            зчитування поля екземпляру класу? На жаль, сучасні процесори і


                                                        190
   186   187   188   189   190   191   192   193   194   195   196