Странное исключение 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 . Я знаю, что параллелизм используется неправильно , но это делается специально .

Я пытался отыскать исключение в Google, но почти не нашел информации.

Можете ли вы воспроизвести такое же исключение?

Я использую oracle jdk 1.8.0_40

EDIT:

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

27 голосов | спросил pnadczuk 30 PMpThu, 30 Apr 2015 15:08:38 +030008Thursday 2015, 15:08:38

2 ответа


0

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

ответил HyperNeutrino 30 PMpThu, 30 Apr 2015 18:00:55 +030000Thursday 2015, 18:00:55
0

Я получал то же самое ClassCastException с одновременными вызовами HashMap.computeIfAbsent . Я исправил это, изменив имплментацию на использование ConcurrentHashMap .

ответил Clay 23 J0000006Europe/Moscow 2018, 06:24:36

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

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132