Page 253 - 6253
P. 253

одночасно намагаються виконати наступну операцію:

                  accounts[to] = accounts[to] + amount;
                  Проте дана операція не є атомарною і може бути виконана поетапно наступним

            чином:

                  1) завантажити значення елемента accounts[to]з масиву в регістр;

                  2) додати до нього значення змінної amount;

                  3) записати результат назад в масив на місце елемента accounts[to].

                  Представимо,  що  в  першому  потоці  виконуються  операції  1  та  2,  після  чого

            його  виконання  призупиняється.  Припустимо,  що  другий  потік  виходить  із  стану

            очікування  і  оновлює  той  же  самий  елемент  у  масиві  accounts.  Потім  виходить  із

            стану очікування перший потік і виконує операцію під номером 3. Дана дія затирає

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

            підрахованим невірно.

                  Суть  розглянутої  проблеми  полягає  в  тому,  що  виконання  методу  transfer()

            може бути перервано на півдорозі до завершення його виконання. Для того щоб стан

            об’єкта  банківського  рахунку  не  був  порушений,  потрібно  гарантувати  нормальне

            завершення методу transfer() до того, як його потік втратить керування.



                    10.4.3 Використання об’єктів блокування

                  У  мові  Java  існує  два  механізми  для  захисту  критичної  секції  коду  від

            паралельного  доступу.  Один  із  них  полягає  у  використанні  ключового  слова

            synchronized,  а  інший  –  у  використанні  класу  ReentrantLock,  що  з’явився  у  версії

            JavaSE 5.0.  Ключове  слово  synchronized  автоматично  забезпечує  блокування,  як  і


            пов’язана  з  ним  умова,  яку  зручно  використовувати  в  більшості  випадків,  коли
            необхідно реалізувати явне блокування.



                  Захист блоку коду засобами класу ReentrantLock в загальному випадку виглядає

            наступним чином:

                  myLock.lock(); // об’єкт типу ReentrantLock
                  try {

                     критична секція коду;
                  } finally {
                     // зняти блокування, навіть у випадку генерації винятку




                                                              252
   248   249   250   251   252   253   254   255   256   257   258