Я пытаюсь исправить ошибку, связанную с ConcurrentModificationException
во время итерации Collections.synchronizedMap
.Будет ли Collections.synchronizedMap быть потокобезопасным, если синхронизируется во время итерации?
Как запросил Javadoc, процесс итерации был синхронизирован на карте.
Я проверил процесс итерации, нет очевидной модификации размера карты (метод, вызывающий трассировку, очень длинный, который я буду проверять дважды).
Помимо изменения во время процесса итерации есть ли другая возможность, которая может вызвать это исключение?
Поскольку итерация уже синхронизирована, из моего понимания, другая нить не сможет вносить изменения, такие как add()
или remove()
, это правильно?
Я действительно новичок в этих вещах. Любая помощь будет действительно оценена.
Обновление
Спасибо так много для всех о помощи особенно подробные объяснения от @ Marco13. Я сделал небольшой код, чтобы проверить и проверить эту проблему, и код прилагается здесь:
public class TestCME {
public static void main(String[] args){
TestMap tm = new TestMap();
for(int i = 0;i < 50;i++){
tm.addCity(i,new City(i * 10));
}
RunnableA rA = new RunnableA(tm);
new Thread(rA).start();
RunnableB rB = new RunnableB(tm);
new Thread(rB).start();
}
}
class TestMap{
Map<Integer,City> cityMap;
public TestMap(){
cityMap = Collections.synchronizedMap(new HashMap<Integer,City>());
}
public Set<Integer> getAllKeys(){
return cityMap.keySet();
}
public City getCity(int id){
return cityMap.get(id);
}
public void addCity(int id,City city){
cityMap.put(id,city);
}
public void removeCity(int id){
cityMap.remove(id);
}
}
class City{
int area;
public City(int area){
this.area = area;
}
}
class RunnableA implements Runnable{
TestMap tm;
public RunnableA(TestMap tm){
this.tm = tm;
}
public void run(){
System.out.println("Thread A is starting to run......");
if(tm != null && tm.cityMap != null && tm.cityMap.size() > 0){
synchronized (tm.cityMap){
Set<Integer> idSet = tm.getAllKeys();
Iterator<Integer> itr = idSet.iterator();
while(itr.hasNext()){
System.out.println("Entering while loop.....");
Integer id = itr.next();
System.out.println(tm.getCity(id).area);
try{
Thread.sleep(100);
}catch(Exception e){
e.printStackTrace();
}
}
}
/*Set<Integer> idSet = tm.getAllKeys();
Iterator<Integer> itr = idSet.iterator();
while(itr.hasNext()){
System.out.println("Entering while loop.....");
Integer id = itr.next();
System.out.println(tm.getCity(id).area);
try{
Thread.sleep(100);
}catch(Exception e){
e.printStackTrace();
}
}*/
}
}
}
class RunnableB implements Runnable{
TestMap tm;
public RunnableB(TestMap tm){
this.tm = tm;
}
public void run(){
System.out.println("Thread B is starting to run......");
System.out.println("Trying to add elements to map....");
tm.addCity(50,new City(500));
System.out.println("Trying to remove elements from map....");
tm.removeCity(1);
}
}
Я пытался восстановить свою ошибку, так что код является немного длинным, и я извиняюсь за это. В потоке А я делаю итерацию на карте, в то время как в потоке B я пытаюсь добавить и удалить элементы из карты. При правильной синхронизации на карте (как сообщается @ Marco13) я не увижу ConcurrentModificationException, если без синхронизации или синхронизации на объекте TestMap появляется исключение. Наверное, я сейчас понимаю эту проблему. Любое двойное подтверждение или предложение по этому поводу очень приветствуется. Еще раз спасибо.
Предлагаю вам разместить автономный, воспроизводимый пример и соответствующую трассировку стека, иначе вам будет сложно помочь, и ваш вопрос может быть закрыт. – Mena
Если вы держите замок, есть только два способа: как карта может быть изменена, 1. потоком, которому принадлежит блокировка, 2. через ссылку на исходную карту, которая была обернута 'Collections.synchronizedMap' , Чтобы избежать второго варианта, вы не должны ссылаться на завернутую карту. Что касается первого, поможет только тщательный анализ кода. – Holger
Большое спасибо за комментарии. Я добавил пример кода, который генерирует исключение. Сейчас я делаю анализ кода. По второй причине вы могли бы дать мне более подробную информацию или документы? Я не очень понимаю обернутую карту. Большое спасибо. – alice