Это было сделано миллион раз. Я уверен, но мой поиск foo сегодня слаб, и я хотел бы получить мнения о том, что обычно считается best способ достижения этой цели.Блокировка записей БД для параллелизма между потоками
Мое приложение отслеживает сеансы для пользователей онлайн в системе. Каждый сеанс соответствует одной записи в базе данных. Сессию можно завершить одним из двух способов. Получается сообщение «stop», или сеанс может быть тайм-аутом. Первый случай прост, он обрабатывается в потоке обработки сообщений, и все в порядке. В последнем случае возникает проблема.
Для обработки тайм-аутов каждая запись имеет столбец окончания времени, который обновляется каждый раз, когда сообщение принимается для этого сеанса. Чтобы сделать тайм-ауты, у меня есть поток, который возвращает все записи из базы данных, время окончания которой < NOW() (имеет время окончания в прошлом) и проходит обработку для закрытия этих сеансов. Проблема здесь в том, что возможно, что я могу получить сообщение для сеанса, в то время как поток тайм-аута проходит обработку для того же сеанса. Я заканчиваю гонку между потоком таймаута и потоком обработки сообщений.
Я мог бы использовать семафор или подобное и просто предотвращать обработку потока сообщений, пока происходит тайм-аут, поскольку он должен запускаться только каждые 30 секунд или минуту. Однако, поскольку таблица пользователей становится большой, это может столкнуться с серьезными проблемами производительности. Я думаю, что мне хотелось бы узнать, как в потоке сообщений эта запись обрабатывается потоком таймаута. Если бы я мог добиться этого, я мог бы либо отбросить сообщение, либо дождаться окончания потока времени, но только в случае конфликтов сейчас, а не всегда.
В настоящее время мое приложение напрямую использует JDBC. Был бы более простой/стандартный метод для решения этой проблемы, если бы я использовал инфраструктуру, такую как Hibernate?
Вы можете обернуть свой семафор идентификатором сеанса вместо уровня потока, так что у вас есть синхронизированные (sessionID) блоки в обработчике сообщений и в части завершения работы таймаута. Я не думаю, что он настолько чист, насколько вам хочется, но он будет иметь меньшее влияние на производительность, чем блокирование целых потоков на одном семафоре, поскольку блокируются только сообщения для этого сеанса. – Thomas
Как это будет работать? Я понимаю, что это будет блокироваться с * object * sessionID, а не * значением * sessionID. Поскольку объекты, созданные в двух потоках после чтения БД, не являются тем же самым объектом, это похоже на то, что он никогда не блокирует. Если у вас есть поле для объекта блокировки и обновлено его из двух потоков перед синхронизированным блоком, у вас есть все те же проблемы с параллелизмом, которые у вас были до этого, просто с фокусом, переключенным на объект блокировки. Если есть способ синхронизировать блок по значению *, о котором я не знаю? – tdimmig
Ответ меняется в зависимости от вашей структуры. Если у вас есть mysession.handleMessage (x) и mysession.closeAndCleanup(), вы должны иметь возможность блокировать mysession. Условия гонки состоят в том, что если сообщение получено после того, как сессия помечена как закрытая, но до того, как она попадет в блок синхронизации, сообщение будет обработано, а сеанс будет закрыт или сеанс будет закрыт, и сообщение вернет ошибку о тайм-ауте , Если структура - это handlemessage (ID, msg) и close (ID), где ID - это просто int, вам понадобится Карта или что-то, что можно синхронизировать. – Thomas