2013-09-11 2 views
1

Я использую итератор для удаления снаряда из списка, если он выходит за границу моего JPanel. Прежде чем использовать итератор, он не сработает, но с итератором он работает до тех пор, пока я помещу метод в try-catch для ConcurrentModificationException. Код теперь работает и успешно удаляет снаряд из списка, но примерно в 30% случаев, хиты хитов и вызывает заикание в моей программе. Я не знаю, почему он только ловит спорадически, но в ограниченное время, которое мой профессор смог посмотреть на него, он думал, что это может быть проблема синхронизации.TryCatch ConcurrentModificationException catching `30% времени

Вот цикл запуска моей программы:

private void executeGameLoop() 
     { 

      long nextFrameStart = System.nanoTime(); 
      while(panel.getRunning()) 
      { 
       do 
       { 
        panel.repaint(); 
        nextFrameStart += FRAME_PERIOD; 
       } while(nextFrameStart < System.nanoTime()); 

       long remaining = nextFrameStart - System.nanoTime(); 
       panel.update(); 

       if (remaining > 0) 
       { 
        try 
        { 
         Thread.sleep(remaining/1000000); 
        } 
        catch(Throwable e) 
        { 
         System.out.println(e.getMessage()); 
        } 
       } 
      } 
     } 

Это называется петлей на panel.update. Он обрабатывает обновления снарядов сейчас:

public void update() 
     {  
      randX = (int)((Math.random() * getWidth()) - (int)(Math.random() * getWidth())); 
      randY = (int)((Math.random() * getHeight()) - (int)(Math.random() * getHeight())); 

      int sizeX; 
      int sizeY; 

      try 
      { 
       Iterator<Projectile> it = shots.iterator(); 
       for(Projectile a : shots) 
       { 
        if(!a.equals(null)) 
        { 
         sizeX = a.getDisplayX(); 
         sizeY = a.getDisplayX(); 

         if((!checkCoords((int)a.getX(), (int)a.getY(), sizeX, sizeY)) && a.hasTarget()) 
         { 
          a = null; 
          if(it.next().equals(null)); 
           it.remove(); 
         } 

         else if(a.hasTarget()) 
         { 
          a.update(); 
         } 
        } 
       } 
      } 
      catch (ConcurrentModificationException e){ System.out.println(e.getMessage() + " Catch"); } 
     } 

Этих последние два метода является моим механизм создания снаряда:

private void createProjectile(int x, int y) 
{ 
    total++; 
    if(shots.size() < shotCount) 
    { 
     Projectile temp = new Projectile(randX, randY); 
     temp.setTarget((x + temp.getSprite().getDisplayImg().getWidth()/8), 
         (y - temp.getSprite().getDisplayImg().getHeight()/8)); 
     temp.setHasTarget(true); 
     shots.add(temp); 
     msg("Target: (" + x + ", " + y + ")"); 
    } 
} 

@Override 
public void mouseClicked(MouseEvent e) 
{ 
    createProjectile(e.getX(), e.getY()); 
} 

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

+6

Вы должны работать над предотвращением причины ConcurrentModificationException, а не ловли его. – Sinkingpoint

+1

И вы должны опубликовать трассировку стека. – chrylis

+1

FWIW, у вас есть две основные проблемы, которые, как правило, вызывают 'ConcurrentModificationException'. Вам нужно исправить как проблему, которую я идентифицировал, так и один найденный @dnault. – chrylis

ответ

5

У вас есть в вашем for цикле открытой Iterator (плюс дополнительные Iterator it), и вы добавляете значения в createProjectile. Вам нужно либо сделать оба блока synchronized на shots, или (моя рекомендация) сделать копию shots сделать свой рисунок из:

List<Projectile> shotsToPaint; 
synchronized(shots) { shotsToPaint = [`ImmutableList`][1].copyOf(shots); } 

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

+1

+1 для копирования списка и итерации по копии – dnault

+0

@dnault +1?;-) – chrylis

+0

Спасибо за помощь, я не знал, что в цикле подразумевается «Итератор», как указано в dnault. Используя этот подразумеваемый «Итератор», удалите проблемы «ConcurrentModificationException». Тем не менее, я все еще очень неопытен с любой синхронизацией. Можете ли вы указать мне направление, чтобы научиться применять Синхронизацию здесь? – Caboose

2

Цикл for является одной из проблем. При создании цикла, как это:

for (Projectile a : shots) {...} 

компилятор неявно преобразует его:

for (Iterator<Projectile> i = shots.iterator; i.hasNext();) { 
    Projectile a = i.next(); 
    ... 
} 

Таким образом, в общей сложности у вас есть два итератора. Первый создается при явном вызове shots.iterator(), а второй создается неявным образом компилятором в цикле for.

Одна из причин ConcurrentModificationException - это когда кто-то другой изменяет список одновременно с повторением. Ваш профессор предположил проблему синхронизации, потому что обычно «кто-то другой» находится в другом потоке, но в этом случае «Кто-то еще» является другим итератором.

РЕДАКТИРОВАТЬ: Как отметил хрилис, есть и помехи от другой нити.

Смежные вопросы