Вопрос по java, concurrency – Проблема параллелизма Hashmap

29

У меня есть Hashmap, который по соображениям скорости я бы не хотел блокировать. Будет ли обновление и доступ к нему одновременно причиной возникновения проблем, если я не возражаю против устаревших данных?

Мой доступ получает, не перебирает его, а удаления являются частью обновлений.

Или они? [Нужно больше сна] Michael Myers♦
Ваши обновления включают в себя удаление? Ваш доступ включает итерацию, хотя это? Michael Myers♦
Неважно, я думаю, что эти вопросы не имеют значения. Michael Myers♦

Ваш Ответ

9   ответов
0

Нет, проблем не будет, если вы сделаете следующее:

Place your data into the HashMap on the first load of a single thread before any multithreading occurs. This is because the process of adding data alters the modcount and is different on the first time you add it (a null will be returned) vs. replacing the data (the old data will be returned, but the modcount will not be altered). Modcount is what makes iterators fail-fast. If you're using get, though, nothing will be iterated on, so it's fine.

Have the same keys throughout your application. Once the application starts and loads its data, no other keys can be assigned to this map. This way a get will either get stale data or data that was inserted fresh - there will be no issues.

7

Условия, которые вы описываете, не будут удовлетвореныHashMap, Поскольку процесс обновления карты не является атомарным, вы можете встретить карту в недопустимом состоянии. Многократные записи могут оставить это в поврежденном состоянии.ConcurrentHashMap (1.5 или позже) делает то, что вы хотите.

10

Да.Очень плохие вещи случится. Например, ваш поток может застрять в бесконечном цикле.

Либо использоватьConcurrentHashMap, или жеNonBlockingHashMap

Я бы не рекомендовал использовать NonBlockingHashMap. Просто используйтеConcurrentHashMap.
16

Важность синхронизации или использованияConcurrentHashMap не может быть преуменьшено.

Вплоть до того, как пару лет назад у меня было ложное впечатление, что я могу обойтись только синхронизацией операций put и remove в HashMap. Это, конечно, очень опасно и фактически приводит к бесконечному циклу в HashMap.get () на некоторых (я думаю, ранних 1.5) jdk.

То, что я сделал пару лет назад (и действительно не должно было быть сделано):

public MyCache {
    private Map<String,Object> map = new HashMap<String,Object>();

    public synchronzied put(String key, Object value){
        map.put(key,value);
    }

    public Object get(String key){
        // can cause in an infinite loop in some JDKs!!
        return map.get(key);
    }
}

EDIT: думал, я бы добавил пример того, чтоnot делать (см. выше)

Я думаю, что бесконечный цикл - это особенность каждого Sun JDK. Я не могу вспомнить, какая часть хорошо известного программного обеспечения с открытым исходным кодом использовала HashMap для ведения журнала, поэтому оставила его несинхронизированным для скорости, так как полная точность не требовалась. В производстве очень редко он попадал в бесконечный цикл - гораздо хуже, чем выбрасывать непроверенное исключение.
Я видел это сам. Если вы попытаетесь обновить HashMap в нескольких потоках, не заботясь о коррупции, это приведет к зависанию JVM. Несинхронизированный / не потокобезопасный HashMap безопасен только в том случае, если вы не обновляете / удаляете или к нему обращается только один поток.
12

Если есть сомнения, проверьте классJavadocs:

Note that this implementation is not synchronized. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map:

Map m = Collections.synchronizedMap(new HashMap(...));

(акцент не мой)

Исходя из того, что вы сказали, что ваши темы будут удалять сопоставления с карты, ответ таков:yes это определенно вызовет проблему, и да, это определенноunsafe.

0

Как и другие упомянутые, используйте ConcurrentHashMap или синхронизируйте карту при обновлении.

55

Да, это вызовет серьезные проблемы. Одним из примеров является то, что может произойти при добавлении значения в хеш-карту: это может вызвать перефразирование таблицы, и если это происходит, когда другой поток выполняет итерацию по списку столкновений (хеш-таблице "bucket"), этот поток может ошибочно не удается найти ключ, который существует на карте.HashMap явно небезопасно для одновременного использования.

использованиеConcurrentHashMap вместо.

4

Если "одновременно" вы имеете в виду из нескольких потоков, тогда да, вам нужно заблокировать доступ к нему (или использовать ConcurrentHashMap или аналогичный, который делает блокировку за вас).

0

Я читаю здесь или где-либо еще, нет, вы не получаете доступ из многопоточности, но никто не говорит, что на самом деле происходит.

Итак, я видел сегодня (вот почему я отвечаю на этот старый вопрос) в приложении, работающем в производстве с марта: 2, поставленный на тот же HashSet (тогда HashMap), вызывает перегрузку ЦП (около 100%), и увеличение памяти на 3 ГБ, затем уменьшение на GC. Мы должны перезапустить приложение.

Похожие вопросы