java-методы и условия гонки в приложении jsp / servlets - PullRequest
2 голосов
/ 04 мая 2010

Предположим, что у меня есть метод с именем doSomething(), и я хочу использовать этот метод в многопоточном приложении (каждый сервлет наследуется от HttpServlet). Мне интересно, возможно ли, что в следующих случаях возникнет условие гонки :

  1. doSomething() является не статическим методом и записывает значения в базу данных.
  2. doSomething() - это статический метод, но он не записывает значения в базу данных.

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

[poll_id |              poll_data        ]
[1       | {choice_1 : 10, choice_2 : 20}]

Будет ли приложение JSP / Servlets самостоятельно решать эти проблемы, или мне придется решать все это самостоятельно?

Спасибо ..

Ответы [ 5 ]

4 голосов
/ 04 мая 2010

Это зависит от того, как doSomething() реализован и что он на самом деле делает. Я предполагаю, что запись в базу данных использует соединения JDBC, которые не поточно-безопасные. Предпочтительный способ сделать это - создать ThreadLocal JDBC-соединения.

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

(Имейте в виду, что просто пометка этих методов как synchronized не исправляет никаких ошибок параллелизма. Если doSomething() увеличивает значение общего объекта, то все обращения к этой переменной должны быть synchronized, поскольку i++ не является атомарной операцией. Если это что-то такое простое, как увеличение счетчика, вы можете использовать AtomicInteger.incrementAndGet().)

3 голосов
/ 04 мая 2010

Servlet API, конечно же, не делает волшебство параллельным для вас.

При записи в базу данных это зависит от стратегии параллелизма на вашем уровне персистентности. Пессимистическая блокировка, оптимистическая блокировка, последние победы? Когда вы «пишете в базу данных», происходит нечто большее, что вам нужно решить, как вы собираетесь работать. Что вы хотите, чтобы произошло, когда два человека одновременно нажали кнопку?

Создание doSomething статичным, похоже, не имеет большого значения для этой проблемы. То, что происходит там, является соответствующей частью. Это изменение статических переменных? Тогда да, могут быть условия гонки.

2 голосов
/ 04 мая 2010

Случай 1, ваш сервлет использует некоторый код, который обращается к базе данных. Базы данных имеют механизмы блокировки, которые вы должны использовать. Для этого есть две важные причины: сама база данных может быть использована другими приложениями, которые читают и записывают эти данные; вашему приложению недостаточно для борьбы с самим собой. И еще: ваше собственное приложение может быть развернуто в масштабированном кластерном веб-контейнере, где несколько копий вашего кода выполняются на разных компьютерах.

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

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

   Start transaction (perhaps implicit, perhaps on entry to an ejb)
   Get connection to  DB ( Gets you a connection from pool, associated with your tran)
   read/write/update code
   Close connection (actually keeps it for your thread until your transaction commits)
   Commit (again maybe implictly)

Таким образом, ваша единственная реальная проблема - иметь дело с любыми конфликтами в БД. Все вышеперечисленное имеет тенденцию быть более приятным, используя такие вещи, как JPA в наши дни, но под прикрытием это более или менее то, что происходит.

Случай 2: статический метод, это, вероятно, подразумевает, что теперь вы храните все в структуре памяти. Это (за исключением какого-либо удаленного вызова) подразумевает одну JVM, и вы сами управляете блокировкой. В случае сбоя вашей JVM или машины, я думаю, вы потеряете свои данные. Если вы заботитесь о своих данных, то лучше использовать БД.

ИЛИ, как насчет совершенно другого подхода: сервлет просто записывает «голос», записывая сообщение в постоянную очередь JMS. Пусть некоторые другие процессы заберут голоса из очереди и сложат их. Вы не дадите немедленную обратную связь избирателю таким образом, но вы отделите опыт пользователя от реальной (в подобных сценариях) довольно сложной обработки.

2 голосов
/ 04 мая 2010

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

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

0 голосов
/ 04 мая 2010

Я считаю, что лучшее решение для вашей проблемы - использовать что-то вроде "синхронизированного" ключевого слова и ждать / уведомлять!

...