2017-02-21 27 views
-1

Если мы не используем Collections.synchronizedMap() и позвольте сказать, что у меня есть многопоточная среда .может hashmap иметь дубликаты ключей в многопотоковой среде

Я знаю о состояние гонки, изменение размера вопроса и т.д.

Мой вопрос может ли быть случай 2 нити Ta и Tb, имеющие тот же объект и пытается поместить в карту.

Может ли быть когда-либо 2 записи, если не так, как это предотвращено. Есть ли разница в времени между двумя вызовами двух разных потоков, выполняемых в одно и то же время.

Как я понимаю, для обоих Ta и Tb оба будут проверять перед помещением, так что может быть случай дубликатов ключей здесь.

Принимая во внимание, что мы переопределили hashcode и equals должным образом.

+0

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

+0

Почему вы спрашиваете? неужели вы не собираетесь использовать контейнер без потоков в таком сценарии? –

+0

Поскольку _both будет проверять перед put_, там у вас есть условие гонки: вставка не является атомной (единственной неделимой) операцией, но она состоит из по крайней мере двух операций, которые могут мешать, когда 'Ta' неправильно синхронизируется с' Tb' , –

ответ

3

Javadoc для HashMap состояний:

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

Так документы говорят, что вы должны синхронизации доступа как-то, но не сказать, что произойдет, если вы этого не сделаете. Это означает, что поведение, когда вы делаете это, - undefined - все ставки отключены.

Вы можете посмотреть на the source code for HashMap самостоятельно. Сердце put является:

 for (Entry<K,V> e = table[i]; e != null; e = e.next) { 
     Object k; 
     if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { 
      V oldValue = e.value; 
      e.value = value; 
      e.recordAccess(this); 
      return oldValue; 
     } 
    } 

    modCount++; 
    addEntry(hash, key, value, i); 
    return null; 

(Edit - это реализация в Java 6. Java 8-х резко отличается - что усиливает точку)

Мы можем спекулировать о результатах, если попытаться два потока это одновременно - но это довольно сложно рассуждать. Иногда это приводит к двум записям с одним и тем же ключом, иногда это не так. Это зависит от времени.

TreeMapput() совершенно по-другому, и его причуды при злоупотреблении таким образом будут разными.

Любое такое поведение является причудой реализации, и реализация может измениться в будущем без предупреждения, потому что мы говорим о неопределенном поведении.Реализация не дает никаких обещаний вам, что это не будет:

  • молча уронить записи
  • идти в бесконечный цикл
  • NullPointerException
  • исковые огромные объемы памяти
  • развратить магазин, так что записи с другими ключами теряются
  • сделать ранее удаленные записи повторно отображаться
  • создавать записи, содержащие мусор из кучи m Эморите
  • т.д.

Документов сделать состояния, модификации из других мест, в то время как Iterator работает на объекте, заставят Iterator, чтобы бросить ConcurrentModificationException - но это другая забота от синхронизация и может произойти, если вы использовали SynchronizedMap

Подводя итог, не делайте этого.