logo search
Хабибуллин

Синхронизация подпроцессов

Основная сложность при написании программ, в которых работают несколько подпроцессов, — это согласовать совместную работу подпроцессов с общими ячейками памяти.

Классический пример — банковская транзакция, в которой изменяется остаток на счету клиента с номером numDep. Предположим, что для ее выполнения запрограммированы такие действия:

Deposit myDep = getDeposit(numDep);

//

Получаем счет с номером numDep

int rest = myDep.getRest();

//

Получаем остаток на счету myDep

rest += sum;

// Изменяем остаток на величину sum

myDep.setRest(rest);

// Заносим новый остаток на счет myDep

Пусть на счету лежит 1000 рублей. Мы решили снять со счета 500 рублей, а в это же время поступил почтовый перевод на 1500 рублей. Эти действия выполняют разные подпроцессы, но изменяют они один и тот же счет myDep с номером numDep. Посмотрев еще раз на рис. 22.1 и 22.2, вы поверите, что последовательность действий может сложиться так. Первый подпроцесс проделает вычитание 1000 – 500, в это время второй подпроцесс выполнит все три действия и запишет на счет 1000 + 1500 = 2500 рублей, после чего первый подпроцесс выполнит свое последнее действие setRest() и у нас на счету окажется 500 рублей. Вряд ли вам понравится такое выполнение двух транзакций.

В языке Java принят выход из этого положения, называемый в теории операционных систем монитором (monitor). Он заключается в том, что подпроцесс блокирует объект, с которым работает, чтобы другие подпроцессы не могли обратиться к данному объекту, пока блокировка не будет снята. В нашем примере первый подпроцесс должен вначале заблокировать счет myDep, затем полностью выполнить всю транзакцию и снять блокировку. Второй подпроцесс приостановится и станет ждать, пока блокировка не будет снята, после чего начнет работать с объектом myDep.

Все это делается одним оператором synchronized(){}, как показано ниже:

Deposit myDep = getDeposit(numDep); synchronized(myDep){

int rest = myDep.getRest(); rest += sum; myDep.setRest(rest);

}

В заголовке оператора synchronized в скобках указывается ссылка на объект, который будет заблокирован перед выполнением блока. Объект будет недоступен для других подпроцессов, пока выполняется блок. После выполнения блока блокировка снимается.