Исключение Strange HashMap (HashMap $Node нельзя передать в HashMap $TreeNode)
После другого вопроса, заданного в stackoverflow,
(Java- Почему эта программа не бросает параллельное исключение модификации)
Я начал экспериментировать с HashMap. Вот несколько строк кода, которые я написал:
import java.util.HashMap;
import java.util.Random;
public class Concurrency {
public static void putEntriesToMap(HashMap<String, String> hashMap) {
for (int count = 0; count < 10000; count++) {
hashMap.put(Integer.toString(count), Integer.toString(count));
Random random = new Random();
if (random.nextBoolean()) {
hashMap.remove(count + "");
}
}
}
public static void main(String[] args) throws InterruptedException {
final HashMap<String, String> hashMap = new HashMap<String, String>();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
putEntriesToMap(hashMap);
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
putEntriesToMap(hashMap);
}
});
t1.start();
t2.start();
t1.join();
t2.join();
}
}
Когда-то (примерно 1 из 20 запусков) при выполнении этого кода я получаю
Exception in thread "Thread-0" Exception in thread "Thread-1" java.lang.ClassCastException: java.util.HashMap$Node cannot be cast to java.util.HashMap$TreeNode
at java.util.HashMap$TreeNode.moveRootToFront(HashMap.java:1819)
at java.util.HashMap$TreeNode.treeify(HashMap.java:1936)
at java.util.HashMap.treeifyBin(HashMap.java:771)
at java.util.HashMap.putVal(HashMap.java:643)
at java.util.HashMap.put(HashMap.java:611)
at Concurrency.putEntriesToMap(Concurrency.java:9)
at Concurrency$1.run(Concurrency.java:27)
at java.lang.Thread.run(Thread.java:745)
Это, однако, кажется мне странным, потому что похоже, что это внутренняя ошибка HashMap.
Я знаю, что concurrency не используется правильно, но он сделан специально.
Я попытался сделать исключение Google, но я почти ничего не нашел.
Можно ли воспроизвести одно и то же исключение?
Я использую oracle jdk 1.8.0_40
EDIT:
Во-первых, спасибо за ответы, теперь это ясно для меня.
Я просто хочу указать, что я знал, как избежать взлома программы, используя безопасные меры потока, но я не знал, почему именно это исключение выбрасывается в данной ситуации.
Томас объяснил это очень хорошо в комментариях ниже. Это также хорошо объяснено в принятом ответе. Еще раз спасибо:).
Ответы
Ответ 1
Я также нашел то же исключение с вашим кодом. Я добавил модификатор synchronized
в метод putEntriesToMap()
, и ошибка, казалось, прекратилась. Проблема в том, что оба потока одновременно изменяют одну и ту же карту. Существует объект, который должен быть преобразован для ввода записи. Однако второй поток имеет дело с мутированным объектом, который выдает a ClassCastException
. Поэтому убедитесь, что ни один из двух потоков не обращается к одной карте одновременно. Модификатор synchronized
останавливает все остальные потоки от выполнения чего-либо с классом/экземпляром, если другой поток делает то же самое. Синхронизированные статические методы синхронизируют сам класс, тогда как синхронизированные нестатические методы только синхронизируют экземпляр класса.