Как правильно задал вопрос BalusC, большой вопрос в том, на каком уровне детализации вы хотели бы сделать эту блокировку? Для каждого вошедшего в систему пользователя, для всех пользователей, или, возможно, вы могли бы избежать блокировки по запросу?
Или, и это будет сложнее, идея о том, что один запрос страницы захватывает блокировку, а затем эта конкретная страница предназначена для сохранения блокировки между запросами? Например. как своего рода оговорка. Я просматриваю страницу отеля, и когда я просто смотрю на комнату, я сделал неявное бронирование в системе для этой комнаты, чтобы не могло случиться, что кто-то другой зарезервирует комнату по-настоящему, пока я смотрю на нее?
В последнем случае, возможно, будет работать следующая схема:
- В области приложения определите глобальную параллельную карту.
- Ключи карты представляют ресурсы, которые вы хотите защитить.
- Значения карты - это пользовательская структура, которая содержит блокировку чтения-записи (например, ReentrantReadWriteLock), токен и отметку времени.
- В области применения также существует одна глобальная блокировка (например, ReentrantLock)
- Код в запросе сначала захватывает глобальную блокировку и быстро проверяет, есть ли запись на карте.
- Если запись есть, она берется, в противном случае она создается. Время создания должно быть очень коротким. Глобальная блокировка быстро снимается.
- Если запись была новой, она блокируется с помощью блокировки записи, и создаются новый токен и отметка времени.
- Если запись не была новой, она блокируется с помощью блокировки чтения
- если код имеет тот же токен, он может пойти дальше и получить доступ к защищенному ресурсу, в противном случае он проверяет метку времени.
- Если отметка времени истекла, она пытается получить блокировку записи.
- Время блокировки записи истекло. Когда наступает тайм-аут, сдавайтесь и сообщайте что-нибудь клиенту. В противном случае создаются новый токен и метка времени.
Это всего лишь общая идея. В приложении Java EE, которое я собираю, я использовал нечто подобное (хотя и не совсем то же самое), и оно работало довольно хорошо.
В качестве альтернативы вы можете в любом случае использовать кварцевое задание, которое периодически удаляет устаревшие записи. Еще одной альтернативой для этого является замена глобальной параллельной карты, например, на. экземпляр JBoss Cache или Infinispan. Они позволяют вам определять политику выселения для их записей, что избавляет вас от необходимости кодировать это самостоятельно. Если вы никогда не использовали эти кеши, то узнать, как их настроить и правильно настроить, может оказаться гораздо сложнее, чем просто создать простую кварцевую работу самостоятельно.