Page 246 - 6571
P. 246

Під час виконання даної програми, невідомо, яка саме сума
                  знаходиться  на  будь-якому  банківському  рахунку  в  довільний
                  момент часу. Але в той же час відомо, що загальна сума грошей
                  за  всіма  рахунками  повинна  залишатися  незмінною,  оскільки

                  гроші тільки переводяться з одного рахунку на інший, але не зні-
                  маються  остаточно.  Наприкінці  кожної  транзакції  метод  tran

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

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

                  виконати наступну операцію:
                        account1 = account1 - amount;

                        Проте  дана  операція  не  є  атомарною  і  може  бути  виконана

                  поетапно наступним чином:
                        1) завантажити значення поля account1 в регістр;
                        2) додати до нього значення змінної amount;

                        3) записати результат назад у поле account1.
                        Представимо, що в першому потоці виконуються операції 1

                  та 2, після чого його виконання призупиняється. Припустимо, що
                  другий потік виходить із стану очікування і оновлює те ж саме
                  поле account1. Потім виходить із стану очікування перший по-

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

                        Суть  розглянутої  проблеми  полягає  в  тому,  що  виконання
                  методу transfer() може бути перервано на півдорозі до заве-
                  ршення його виконання. Для того, щоб стан об’єкта банківського

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

                        У мові Java існує два механізми для захисту критичної секції
                  коду  від  паралельного  доступу.  Один  із  них  полягає  у
                  використанні  ключового  слова  synchronized,  а  інший  –  у

                  використанні  класу  ReentrantLock,  який  реалізує  інтерфейс
                  Lock що з’явився у версії JavaSE 5.0.


                                                             245
   241   242   243   244   245   246   247   248   249   250   251