Проблема параллелизма Hashmap

Это побитовый оператор xor в java, который приводит к 1 для разного значения бит (т. е. 1 ^ 0 = 1) и 0 для одного значения бита (т. е. 0 ^ 0 = 0), когда число записывается в двоичной форме .

ex: -

Чтобы использовать ваш пример:

Бинарное представление 5 равно 0101. Бинарное представление 4 равно 0100.

Простым способом определения Побитового XOR является утверждение, что результат имеет 1 в каждом месте, где два входных числа отличаются.

0101 ^ 0100 = 0001 (5 ^ 4 = 1).

29
задан Jon Erickson 16 June 2009 в 21:36
поделиться

9 ответов

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

Используйте вместо этого ConcurrentHashMap .

55
ответ дан erickson 16 June 2009 в 21:36
поделиться

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

Либо используйте ConcurrentHashMap , либо NonBlockingHashMap

10
ответ дан ykaganovich 16 June 2009 в 21:36
поделиться

В случае сомнений проверьте Javadocs класса :

. Обратите внимание, что эта реализация не синхронизирована. Если несколько потоков обращаются к хэш-карте одновременно, и хотя бы один из потоков структурно изменяет карту, она должна быть синхронизирована извне. (Структурная модификация - это любая операция, которая добавляет или удаляет одно или несколько сопоставлений; простое изменение значения, связанного с ключом, который уже содержится в экземпляре, не является структурной модификацией.) Обычно это выполняется путем синхронизации с некоторым объектом, который естественным образом инкапсулирует карту , Если такого объекта не существует, карту следует «обернуть» с помощью метода Collections.synchronizedMap. Это лучше всего сделать во время создания, чтобы предотвратить случайный несинхронизированный доступ к карте:

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

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

Таким образом, на основе тот факт, что вы сказали, что ваши потоки будут удалять сопоставления с карты, ответ таков: да это определенно вызовет проблему, и да, это определенно небезопасно .

12
ответ дан matt b 16 June 2009 в 21:36
поделиться

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

До тех пор, пока пару лет назад у меня не было ложного впечатления, мне не удавалось синхронизировать только операции размещения и удаления в 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);
    }
}

РЕДАКТИРОВАТЬ : думал, что я добавлю пример того, что не делать (см. выше)

16
ответ дан Gareth Davis 16 June 2009 в 21:36
поделиться

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

7
ответ дан Kathy Van Stone 16 June 2009 в 21:36
поделиться

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

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

0
ответ дан C.Twins 16 June 2009 в 21:36
поделиться

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

4
ответ дан nos 16 June 2009 в 21:36
поделиться

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

  1. Поместите ваши данные в HashMap при первой загрузке одного потока, прежде чем произойдет какая-либо многопоточность. Это связано с тем, что процесс добавления данных изменяет значение modcount и отличается при первом добавлении (возвращается ноль) и замене данных (старые данные будут возвращены, но modcount не будет изменен). Modcount - это то, что делает итераторы отказоустойчивыми. Однако если вы используете get, ничего не будет повторяться, так что все в порядке.

  2. Используйте одинаковые клавиши во всем приложении. Как только приложение запускается и загружает свои данные, никакие другие ключи не могут быть назначены этой карте. Таким образом, get либо получит устаревшие данные, либо данные, которые были вставлены свежими - проблем не будет.

0
ответ дан MetroidFan2002 16 June 2009 в 21:36
поделиться

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

0
ответ дан 16 June 2009 в 21:36
поделиться
Другие вопросы по тегам:

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