Page 146 - 4868
P. 146

Ошибка! Стиль не определен.                                                              144

               іншому потоці, відмінному від потоку, що виконав виклик метода await(),
               оскільки  він  не  має  можливості  повторно  активізувати  самого  себе.  Якщо
               жоден із потоків не «подбає» про повторну активацію призупиненого потоку,
               то його виконання ніколи не відновиться, що може призвести до так званого
               взаємного  блокування.  Якщо  всі  інші  потоки  будуть  заблоковані,  а  метод
               await() буде викликаний з останнього активного потоку без попереднього

               виклику  методу  signalAll(),  то  даний  потік  також  виявиться
               заблокованим.
                     Що  стосується  виклику  методу  signalAll(),  то  тут  існує  певне
               емпіричне  правило,  яке  говорить,  що  викликати  даний  метод  потрібно  при
               такій зміні стану об’єкта, який може бути вигідний призупиненим потокам.
               Наприклад,  щоразу,  коли  змінюються  залишки  на  рахунках,  потокам  що
               перебувають  в  стані  очікування  слід  надавати  чергову  можливість  для
               перевірки  цих  залишків.  У  представленому  нижче  прикладі  метод
               signalAll() викликається під час завершення переказу коштів.
                     public void transfer(int from, int to, int amount) {
                       bankLock.lock();
                       try {
                         while (accounts[from] < amount)
                           sufficientFunds.await();
                         // переказати кошти
                         sufficientFunds.signalAll();
                       } finally {
                         bankLock.unlock();
                       }
                     }

                     Слід також мати на увазі, що виклик методу signalAll() не спричиняє
               негайну  активацію  призупиненого  потоку.  Він  лише  розблокує  потоки,  що
               перебувають  в  стані  очікування,  щоб  вони  мали  можливість  змагатися  за
               об’єкт блокування.
                     Існує також метод signal(), який розблокує  тільки один  потік  із тих
               що перебувають в очікуванні, вибираючи його при цьому випадковим чином.
               Це  більш  ефективно,  ніж  розблоковувати  всі  заблоковані  потоки,  хоча  в
               даному  випадку  існує  певна  небезпека.  Якщо  випадково  обраний  потік
               виявить, що ще не може продовжити свого виконання, то він знову перейде в
               режим  очікування.  І  якщо  жодний  інший  потік  не  викличе  знову  метод
               signal(), то система перейде в стан взаємного блокування.
                     Отже, підведемо короткі підсумки, перерахувавши ключові моменти, що
               стосуються блокувань та умов:
                     1. Блокування захищають критичні секції коду, дозволяючи при цьому
               виконувати даний код тільки одному потоку в конкретний момент часу.
                     2. Блокування  використовуються  для  керування  потоками,  які

               намагаються увійти в захищену секцію коду.
                     3. Кожен  умовний  об’єкт  керує  потоками,  які  увійшли  в  захищену
   141   142   143   144   145   146   147   148   149   150   151