Использовать элементы из ConcurrentHashMap

Я использую ConcurrentHashMap для буферизации сообщений для веб-сокета.

Каждые 200 мс буфер отправляется в одной строке JSON. после этого я хочу удалить запись с карты.

Я думаю, это небезопасно, потому что во время foreach в буфер могут приходить новые сообщения.

String sendString;
for(String msg : buffer.values()){
    sendString += msg;
}
ws.send(sendString);
buffer.clear();

Как я могу безопасно удалить элементы?

4 ответа

Вам необходимо проверить ключ и значение.

StringBuilder sendString = new StringBuilder();
for (Map.Entry<String, String> entry : buffer.entrySet()) {
    sendString.append(entry.getValue());
    buffer.remove(entry.getKey(), entry.getValue()); // only remove a matching value
}

Map#remove() возвращает значение, которое существует в карте до удаления. В ConcurrentHashMap это выполняется атомарно, так что вы можете безопасно использовать результат:

StringBuilder sendString = new StringBuilder();
for (String key : buffer.keySet()) {
    String s = buffer.remove(key);
    if (s != null)
        sendString.append(s);
}  

Используйте итератор явно:

StringBuilder result = new StringBuilder();
for (Iterator<String> it = buffer.values().iterator(); it.hasNext(); ) {
    result.append(it.next());
    it.remove();
}

Поместите весь блок метода в синхронизированный блок. Никакой другой поток не может писать на карту во время выполнения этого кода.

synchronized(buffer){
    String sendString;
    for(String msg : buffer.values()){
        sendString += msg;
    }
    ws.send(sendString);
    buffer.clear();
}

synchronized(buffer){
   buffer.put(key, msg);
}
Другие вопросы по тегам