Если мы однозначно знаем, что разные потоки не могут одновременно выполнять операции get, put и remove с одним и тем же элементом HashMap, при этом другие потоки могут в это же время работать с другими элементами; можно ли в таком случае использовать простую карту, а не потокобезопасную ConcurrentHashMap? Какое решение лучше всего подходит для таких задач?
Недетерминировано работает. Без синхронизации между потоками у нас нет гарантий последовательность и видимости, так что даже без одновременного вызова мутирующих методов есть шанс сломать инвариант.
My1Name, нет, ConcurrentHashMap не создаёт копий. Его гарантии основаны на работе striped lock - по сути обычная блокировка, но на каждый отдельный бакет.
Сергей Горностаев, Однако, несмотря на то, что все операции являются потокобезопасными, операции извлечения не влекут за собой блокировку...
Проще говоря: Я сейчас пишу чат и поймал такую ситуацию, когда пользователю пришло два одинаковых сообщения. История сообщений пишется в файл в том же методе, где сообщения перекладываются в карту... При этом в файл записалось одно сообщение.
However, even though all operations are thread-safe, retrieval operations do not entail locking, and there is not any support for locking the entire table in a way that prevents all access.
Вот это как раз то, что позволяет ConcurrentHashMap быть быстрой. Это не минус и не фактор влияющий как-либо на поведение. Даже не представляю, как это может повлияют на получение двух сообщений. Есть уверенность, что это именно из-за map'ы?
Уверен на 99% Я использую SseEmitter и, думаю что данные не успели перезаписаться... Любое новое сообщение put - делает перезапись. После извлечения, за методом get - следует put(id, ""); Я не делаю remove до тех пор, пока связь не будет разорвана...
Сергей Горностаев, спасибо, думаю нашёл решение, перенеся метод put(id, ""); в spin. Он у меня был немного ниже нужной последовательности: Сразу после отправки, а не после изъятия данных.