В КУРСЕ?

Разбираемся в теме

Один сервлет, два запроса: откуда берётся чужое значение в ответе?

Серверный обработчик может успешно работать при одиночной проверке и ошибаться, когда приходят два запроса почти одновременно. Причина бывает в том, что временные данные сохранены в общем месте. Разберём модель сервлета и порядок действий двух запросов без подключения к серверу. Пример относится к управлению состоянием, а не к конкретной системе пользователей.

Определите, кому принадлежит значение

Сервлеты обычно работают на многопоточных серверах и должны учитывать конкурентные запросы. Поля экземпляра и статические поля могут быть общими для нескольких выполняющихся действий. Поэтому поле с удобным названием текущий товар не становится автоматически личным состоянием одного запроса. Представим вымышленный обработчик каталога. Запрос А просит описание чая, а запрос Б описание какао. Программист сначала записывает выбранное название в поле компонента, а позднее читает его для формирования ответа. При одиночном вызове всё может выглядеть правильно: записали чай и прочитали чай. Но проверка одного запроса не показывает, что произойдёт, если между этими действиями выполнится часть другого запроса.

Разложите выполнение на отдельные шаги

Рассмотрим возможный порядок. Сначала запрос А записывает чай в общее поле. Затем запрос Б записывает туда какао. После этого запрос А читает поле и получает какао. Каждый отдельный шаг выглядит простым, но вместе они нарушают соответствие запроса и ответа. Для возникновения проблемы не требуется, чтобы оба действия произошли буквально в одну и ту же мгновенную точку. Достаточно их чередования с доступом к общему изменяемому состоянию. Из примера не следует, что ошибка будет появляться каждый раз. Другой порядок выполнения может случайно дать ожидаемый результат. Поэтому многократный успех ручной одиночной проверки ещё не доказывает корректность конкурентной работы. Полезно рисовать две последовательности действий рядом и отмечать обращения к одному месту хранения. Такой разбор делает зависимость видимой до запуска сложной системы.

Сокращайте ненужное общее состояние

Данные, необходимые только для обработки конкретного запроса, обычно следует сохранять в его контексте или локальных переменных соответствующего выполнения. В нашем примере название товара не требуется хранить в общем поле сервлета. Однако локальная переменная может содержать ссылку на общий изменяемый объект. Само перемещение ссылки в локальную область не делает этот объект независимым. Нужно проследить, где находится состояние и кто ещё способен его менять. Состояние сессии тоже не означает автоматического отсутствия конкуренции: к общим объектам могут обращаться несколько запросов. Файлы, соединения и другие совместно используемые ресурсы требуют отдельного продуманного управления. Синхронизация является инструментом для определённых задач, но добавлять блокировку вокруг всего обработчика без анализа не стоит. Сначала выясняют, зачем состояние общее, какие действия должны быть согласованы и можно ли избежать совместного изменения. Проверка исправления должна включать сценарии чередования, а не только обычный успешный ответ. Для нашей бумажной модели достаточно убедиться, что запрос А использует собственное выбранное значение независимо от того, когда выполняется запрос Б. Такой анализ не заменяет полноценного тестирования приложения, но помогает найти ошибку в самом устройстве данных.

Попробуйте на практике

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

  1. Создайте два столбца для запросов А и Б. Укажите их независимые значения: чай и какао.
  2. Запишите порядок: А меняет общее поле, Б меняет его, А читает. Определите, какое значение получит А.
  3. Измените модель так, чтобы каждый запрос сохранял собственное название в своём контексте. Повторите тот же порядок действий.
  4. Добавьте вопрос о ссылке на общий объект: будет ли он независимым только потому, что ссылка находится в локальной переменной?

Как проверить результат. В исходной модели обнаружена подмена значения, в исправленной запросы сохраняют собственные данные. Локальная ссылка не приравнена к отдельному объекту.

Частые вопросы

Если запросы проходят по одному, ошибка устранена?

Нет. Это не проверяет конкурентное чередование. Нужно анализировать доступ к общему состоянию и соответствующие сценарии.

Любое поле сервлета обязательно является ошибкой?

Нет. Важно его назначение, изменяемость и способ совместного использования. Опасно без анализа хранить в общем поле временные данные конкретного запроса.

Самостоятельный разбор темы. Содержание конкретной обучающей программы здесь не представлено.

Зарегистрируйтесь, чтобы уточнить возможность доступа к этому материалу

Зарегистрироваться
← К списку материалов