Подтвердить что ты не робот

Исключение 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:

Во-первых, спасибо за ответы, теперь это ясно для меня. Я просто хочу указать, что я знал, как избежать взлома программы, используя безопасные меры потока, но я не знал, почему именно это исключение выбрасывается в данной ситуации. Томас объяснил это очень хорошо в комментариях ниже. Это также хорошо объяснено в принятом ответе. Еще раз спасибо:).

4b9b3361

Ответ 1

Я также нашел то же исключение с вашим кодом. Я добавил модификатор synchronized в метод putEntriesToMap(), и ошибка, казалось, прекратилась. Проблема в том, что оба потока одновременно изменяют одну и ту же карту. Существует объект, который должен быть преобразован для ввода записи. Однако второй поток имеет дело с мутированным объектом, который выдает a ClassCastException. Поэтому убедитесь, что ни один из двух потоков не обращается к одной карте одновременно. Модификатор synchronized останавливает все остальные потоки от выполнения чего-либо с классом/экземпляром, если другой поток делает то же самое. Синхронизированные статические методы синхронизируют сам класс, тогда как синхронизированные нестатические методы только синхронизируют экземпляр класса.