Синхронизация потоков в Java - PullRequest
1 голос
/ 02 февраля 2012

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

* 1003 Т.е. *

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

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

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

02-03 02: 47: 43.660: ОШИБКА / AndroidRuntime (5258): необработанный обработчик: выход из основного потока из-за необработанного исключения 02-03 02: 47: 43.670: ОШИБКА / 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): at com.jjg.myapp.gameunit.findEnemy (MoveableUnit.java:656) // <--- в этом методе коллекции Gamestate повторяются 02-03 02: 47: 43.670: ОШИБКА / AndroidRuntime (5258): на com.jjg.myapp.gameunit.update (GameUnit.java:416) </p>

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

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

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

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

Ответы [ 4 ]

1 голос
/ 02 февраля 2012

Вы действительно задаете тот же вопрос, что и этот: Потоковая итерация по коллекции .

Самое простое решение - скопировать список перед итерацией по нему:

for(GameUnit gu : new ArrayList<GameUnit>(this.getBase().getGameState().getAllUnits()))

В качестве альтернативы вы можете синхронизировать саму коллекцию (обратите внимание, что для этого вам также нужно синхронизировать, где бы вы ни изменяли список «всех единиц»):

ArrayList<GameUnit> units = this.getBase().getGameState().getAllUnits())
synchronized (units) {
  ...
}
1 голос
/ 02 февраля 2012

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

0 голосов
/ 02 февраля 2012

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

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

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

  SwingUtilities.invokeLater(new Runnable() {
    public void run() {
       anotherObject.modify();
    }
  });
0 голосов
/ 02 февраля 2012

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

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

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

Поток, имеющий блокировку, снова будет работать, так как блокировкаrentrant.

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

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

...