Это все равно, что избежать ConcurrentModificationException s.
Вы не можете изменять коллекцию во время итерации по ней, иначе будет выдано такое исключение. То, что вы опубликовали, является весьма распространенной идиомой для решения этой проблемы - возьмите копию коллекции тем или иным способом, затем вы можете перебирать одну, изменяя другую.
Это может произойти даже в однопоточном коде - например, что-то вроде этого вызовет это исключение в коллекции, по крайней мере, с двумя элементами:
for (Object o : myCollection)
{
myCollection.remove(o);
}
Альтернативный и, вероятно, более производительный способ решения этой проблемы заключается в явном объявлении Итератора (вместо использования цикла foreach ) и последующем использовании метода Итератора remove, при необходимости. (Однако это не относится к вашему случаю, потому что вы перераспределяете, а не удаляете элементы).
Редактировать: хотя при отражении карта availableIngredients
не зацикливается, поэтому ее можно просто изменить напрямую. Вы правы быть сбитым с толку, как оказалось. :-) Скорее всего, это след от прежнего рефакторинга, но его можно заменить на
public void orderSandwich(SandwichType sandwichType) {
for (Map.Entry<Ingredient, Integer> entry :
sandwichType.getIngredients().entrySet()) {
Integer currentUnits = availableIngredients.get(entry.getKey());
availableIngredients.put(entry.getKey(), currentUnits - entry.getValue());
}
}
как вы, без сомнения, ожидаете.
Мысль, которая только что пришла в голову, состоит в том, что это, возможно, также была ошибочная попытка сделать проблемы параллелизма «менее вероятными», уменьшив окно конфликтующих обновлений. Однако ошибочно, потому что потокобезопасность абсолютна; Создание чего-то в десять раз менее вероятного для демонстрации гонок данных - не хорошее вложение времени. Он все равно будет «случайным образом» и неверен.