LinkedHashMap ConcurrentModificationException Ошибка

В моей java-программе для MUDRPG на данный момент два потока (если не ошибаюсь, движок писал не я). Один поток является чисто графическим и отображает все объекты Gui, а другой поток обрабатывает все вычисления. Этот второй поток отвечает за сражения. В своем боевом коде я проверяю, существует ли графический интерфейс hitsplat, однако после нескольких успешных вызовов функции (каждый раз с другим номером) я застреваю с ошибкой ConcurrentModificationException. Похоже, это потому, что в то время, когда эта битва пытается проверить, существуют ли хитсплаты, графический поток пытается отобразить вещи из LinkedHashMap. Может кто-нибудь, пожалуйста, проинструктируйте меня, как правильно читать из LinkedHashMap, чтобы избежать этой проблемы, или мне нужно вместо этого использовать ConcurrentHashMap? Насколько я понимаю, LinkedHashMap используется, потому что он может обрабатывать порядок, я не совсем уверен, верно ли то же самое для ConcurrentHashMap.

Код, который обращается к LinkedHashMap в потоке вычислений:

private boolean checkHitsplats(){
    System.out.println("I get called)");
    while (true) {
        try {
            if (OneQuest.getInstance().getTickThread().getGuis()
                    .get("HitsplatPlayer") == null
                    && OneQuest.getInstance().getTickThread().getGuis()
                            .get("HitsplatMonster1") == null
                    && OneQuest.getInstance().getTickThread().getGuis()
                            .get("HitsplatMonster2") == null
                    && OneQuest.getInstance().getTickThread().getGuis()
                            .get("HitsplatMonster3") == null) {
                return false; // return false if none exist
            } else
                return true; // return true of any hitsplats exist
        } catch (ConcurrentModificationException e) {
            System.out.println("modification error");
        }
    }
}

Фрагмент кода, который циклически проходит через linkedHashMap для отображения графических элементов, где guis — это LinkedHashMap со всеми добавленными графическими объектами.

private void tick() {
    synchronized (guis) {
        Iterator<Gui> iter = guis.values().iterator();
        while (iter.hasNext()) {
            Gui gui = iter.next();
            if (gui.isShowing()) {
                gui.render(window);
            }
        }
    }
    if (guiConsole.isShowing()) {
        guiConsole.render(window);
    }
}

Изменить: Версия 2 checkHitsplats, предложенная добрым человеком.

private boolean checkHitsplats(){
    Object[] guis = OneQuest.getInstance().getTickThread().getGuis().values().toArray();
    System.out.println("I get called)");

    while (true) {
        try {
            for (int i = 0; i < guis.length; i++) {
                if (((Gui) guis[i]).getGuiName() == "HitsplatPlayer"
                        || ((Gui) guis[i]).getGuiName() == "HitsplatMonster1"
                        || ((Gui) guis[i]).getGuiName() == "HitsplatMonster2"
                        || ((Gui) guis[i]).getGuiName() == "HitsplatMonster3")
                    return true;
            }
            return false;
        } catch (Exception e) {
        }
    }

person Vasu    schedule 10.06.2013    source источник
comment
Пожалуйста, попробуйте использовать: Collections.synchronizedMap(new LinkedHashMap()). Для получения дополнительной информации перейдите по ссылке ниже: docs.oracle. com/javase/6/docs/api/java/util/LinkedHashMap.html Надеюсь, это поможет.   -  person Harish Kumar    schedule 10.06.2013
comment
Вы сравниваете строки с ==! Вы не должны этого делать (даже если это может сработать в вашем конкретном случае, это опасная привычка).   -  person Joachim Sauer    schedule 10.06.2013
comment
Вам нужно предоставить больше информации: как вы создаете экземпляр карты (вставка или порядок доступа)? В какой строке возникает исключение (проверьте сообщение об исключении)?   -  person assylias    schedule 10.06.2013
comment
Вы не должны получать это исключение, если только вы не изменяете свою карту где-то в то же время, особенно в вашем методе checkHitsplats(), который даже не повторяет карту. Вы уверены, что именно здесь выбрасывается исключение? Можете ли вы опубликовать свою трассировку стека?   -  person Artyom    schedule 10.06.2013


Ответы (1)


ConcurrentHashMap не будет выдавать ConcurrentModificationException при переборе, но, как вы заметили, он не отслеживает порядок ключей. Другой вариант - перебрать LinkedHashMap#values.toArray() или LinkedHashMap#entrySet.toArray() - toArray создаст копию коллекции, поэтому повторение возвращаемого массива не вызовет ConcurrentModificationException.

person Zim-Zam O'Pootertoot    schedule 10.06.2013
comment
Хм... как именно работает синтаксис для этого? Если предположить, что у меня есть LinkedHashMap с именем guis, будет ли это: LinkedHashMap#guis.toArray()? - person Vasu; 10.06.2013
comment
Это будет Object[] array = guis.values().toArray() или Object[] array = guis.entrySet().toArray(). Если guis является общей картой, например. LinkedHashMap<K, V> guis, тогда вы можете использовать V[] array = guis.values().toArray(new V[]) или Map.Entry<K,V>[] array = guis.entrySet().toArray(new Map.Entry<K,V>[]) - person Zim-Zam O'Pootertoot; 10.06.2013
comment
Я реализовал ваше предложение, но у меня все еще возникает та же проблема. Пожалуйста, проверьте обновленный OP на наличие нового кода. - person Vasu; 10.06.2013
comment
Вы не можете получить ConcurrentModificationException при переборе массива. Есть ли еще один фрагмент кода, который перебирает LinkedHashMap? Имейте в виду, что любой цикл for-each, перебирающий LinkedHashMap, может выдать ConcurrentModificationException. - person Zim-Zam O'Pootertoot; 10.06.2013