Дизайн сервлета, одновременный доступ к полю

У меня довольно общий вопрос, прошу совета.

У меня есть сервлет.

Этот сервлет имеет приватное поле.

Закрытое поле — это разновидность метаданных (открытый класс Metadata{//bla-bla-bla}).

Когда обрабатывается запрос GET, эти метаданные используются для выполнения некоторой операции.

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

Проблема: одновременный доступ к этому частному полю с объектом метаданных, совместно используемым несколькими веб-потоками с использованием одного экземпляра сервлета. Операция метода POST (Обновить объект метаданных) может привести к несогласованному состоянию метаданных, и одновременный запрос GET может завершиться ошибкой.

Вопрос: как лучше всего обновить объект метаданных во время выполнения запросов GET?

Фиктивное решение:

  1. Во время каждого запроса GET, в самом начале

  2. Синхронизируйте объект метаданных и клонируйте его в одном блоке, затем отпустите.

  3. Параллельные запросы GET работают с клонированной версией объекта метаданных, которая является согласованной.

  4. Во время каждого POST-запроса.

  5. Синхронизируйте объект метаданных и обновите его поля.

  6. Освободить объект метаданных.

Посоветуйте или покритикуйте.


person Capacytron    schedule 12.11.2012    source источник


Ответы (1)


Использование синхронизированных методов set и get в классе метаданных — это нормально, но может замедлить работу вашего веб-приложения, если у вас есть несколько читателей и (намного) меньше авторов:

Синхронизированное ключевое слово Java используется для получения эксклюзивной блокировки объекта. Когда поток получает блокировку объекта либо для чтения, либо для записи, другие потоки должны ждать, пока блокировка этого объекта не будет снята. Подумайте о сценарии, в котором есть много потоков чтения, которые часто считывают общие данные, и только один поток записи, который обновляет общие данные. Нет необходимости блокировать исключительный доступ к общим данным во время чтения, потому что несколько операций чтения могут выполняться параллельно, если нет операции записи.

(Отрывок из этого прекрасного сообщения)

Таким образом, использование стратегии многократного чтения и одной записи может быть лучше с точки зрения производительности в некоторых случаях, как объясняется также в том же Java5 ReadWriteLock:

Блокировка чтения-записи обеспечивает более высокий уровень параллелизма при доступе к общим данным, чем разрешенный блокировкой взаимного исключения. Он использует тот факт, что хотя только один поток за раз (поток записи) может изменять общие данные, во многих случаях любое количество потоков может одновременно читать данные (следовательно, потоки чтения). Теоретически увеличение параллелизма, допускаемое использованием блокировки чтения-записи, приведет к повышению производительности по сравнению с использованием блокировки взаимного исключения. На практике это увеличение параллелизма будет полностью реализовано только на мультипроцессорах, и то только в том случае, если шаблоны доступа к общим данным будут подходящими.

Улучшит ли блокировка чтения-записи производительность по сравнению с блокировкой взаимного исключения, зависит от частоты чтения данных по сравнению с изменением, продолжительности операций чтения и записи и конкуренции за данные. то есть количество потоков, которые будут пытаться читать или записывать данные одновременно. Например, коллекция, которая изначально заполняется данными, а затем нечасто изменяется, но при этом часто просматривается (например, какой-либо каталог), является идеальным кандидатом для использования блокировки чтения-записи. Однако, если обновления становятся частыми, данные проводят большую часть своего времени исключительно заблокированными, и параллелизм практически не увеличивается, если вообще увеличивается. Кроме того, если операции чтения слишком короткие, накладные расходы на реализацию блокировки чтения-записи (которая по своей сути более сложна, чем блокировка взаимного исключения) могут доминировать в стоимости выполнения, особенно потому, что многие реализации блокировки чтения-записи все еще сериализуют все потоки через блокировку. небольшой участок кода. В конечном счете, только профилирование и измерение позволят установить, подходит ли использование блокировки чтения-записи для вашего приложения.

Готовой к использованию реализацией является ReentrantReadWriteLock.

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

person Tony Rad    schedule 12.11.2012
comment
Спасибо. Это именно то, что мне нужно. - person Capacytron; 13.11.2012