Синхронизация потоков в Java

У меня есть два потока, изменяющие один и тот же объект, скажем, MyObject, и поэтому синхронизировали объект. Но в одном из потоков другой объект модифицируется и при этом должен вызывать MyObject.

I.e.

public void run(){
   synchronized(MyObject){
             ...
            anotherObject.modify();//<----calls MyObject
             ...
    }
 }

Это вызывает ConcurrentModificationExceptions. Я не знаю, как это решить. Если я не синхронизируюсь, я получаю исключения, поскольку оба потока пытаются вызвать MyObject. Как я могу это исправить?

ОБНОВЛЕНИЕ: код предназначен для устройства Android. Я не упоминал об этом раньше, потому что здесь нет конкретных объектов для Android. Выход LogCat не очень полезен

02-03 02:47:43.660: ERROR/AndroidRuntime(5258): обработчик необработанных данных: основной поток завершается из-за необработанного исключения 02-03 02:47:43.670: ERROR/AndroidRuntime(5258): java.util.ConcurrentModificationException 02-03 02:47:43.670: ОШИБКА/AndroidRuntime(5258): в java.util.AbstractList$SimpleListIterator.next(AbstractList.java:64) 02-03 02:47:43.670: ОШИБКА/AndroidRuntime(5258): в com.jjg .myapp.gameunit.findEnemy(MoveableUnit.java:656)//‹---в этом методе коллекции Gamestate повторяются через 02-03 02:47:43.670: ERROR/AndroidRuntime(5258): at com.jjg.myapp. gameunit.update(GameUnit.java:416)

Объект, который я пытался синхронизировать, по сути является GameState с именем gs. Он содержит ассортимент ArrayList, массивов и других объектов. gs не статичен.

Метод выше, где возникает проблема:

for(GameUnit gu : this.getBase().getGameState().getAllUnits()){//<---this is the problem line.
//do some stuff...
 }

getAllUnits возвращает ArrayList GameUnits (включая GameUnit, вызывающий метод — мне не нужен итератор, поскольку никакие объекты не удаляются и не создаются).


person Community    schedule 02.02.2012    source источник
comment
Покажите нам настоящий код и трассировку стека исключения. ConcurrentModificationException не может иметь ничего общего с несколькими потоками.   -  person JB Nizet    schedule 02.02.2012
comment
Слишком мало деталей, чтобы дать конкретный совет, относящийся к вашим обстоятельствам. Покажите нам ваш фактический код.   -  person NPE    schedule 02.02.2012
comment
Я обновил его. Я надеюсь, что обновленная информация будет полезна   -  person    schedule 02.02.2012


Ответы (4)



ConcurrentModificationException часто выдается, если коллекция изменяется при использовании на ней итератора. -- Значит, вы ошибаетесь в названии и просто ищите не ту проблему.

person Ralph    schedule 02.02.2012
comment
Я думал, что использование итератора предотвращает Con.Mod.Ex.? Я запутался. - person ; 02.02.2012
comment
@JJG: На самом деле это iterator выдает такое исключение, как только обнаруживает модификацию. Возможно, вы путаете это с тем фактом, что вы можете remove из коллекции с помощью итератора - person Cratylus; 02.02.2012
comment
Кстати: И цикл foreach тоже основан на интераторах. - person Ralph; 02.02.2012
comment
@JJG, из Javadoc: если список структурно изменен в любое время после создания итератора любым способом, кроме как с помощью собственных методов удаления или добавления итератора, итератор выдаст исключение ConcurrentModificationException. Что навело вас на мысль, что итераторы избегают CME? - person Louis Wasserman; 02.02.2012

У меня есть два потока, изменяющие один и тот же объект, скажем, MyObject, и поэтому синхронизировали объект.

Нет, нет. Только 1 поток модифицирует MyObject, другой заблокирован.

Но в одном из потоков другой объект модифицируется и при этом должен вызывать MyObject.

Поток, у которого есть блокировка, будет запущен снова, так как блокировка является арендованной.

Как указано в комментариях, код, который вы публикуете, не показывает, что вы на самом деле делаете, чтобы получить это исключение.

Является ли MyObject Collection? Вы изменяете эту коллекцию в другом месте одновременно, то есть без надлежащей синхронизации?
Или, возможно, итерируете?
В этом случае вы получите исключение, которое вы говорите

person Cratylus    schedule 02.02.2012

Вы не можете этого сделать, это круговая логика.

Вы должны либо вообще избавиться от потоков и определить явный порядок оценки, либо обмениваться данными каким-то другим способом.

Одна из возможных стратегий — поместить вызов «anotherObject.modify» в отдельный исполняемый поток, например:

  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
       anotherObject.modify();
    }
  });
person user1185840    schedule 02.02.2012