Java-Gaming.org Hi !
Featured games (91)
games approved by the League of Dukes
Games in Showcase (764)
Games in Android Showcase (229)
games submitted by our members
Games in WIP (852)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  [Solved] ConcurrentModificationException - How to avoid it  (Read 2453 times)
0 Members and 1 Guest are viewing this topic.
Offline CopyableCougar4
« Posted 2014-06-24 23:10:50 »

Hi

So I have a class called PopUps that renders all PopUp objects, or if they have been marked disposed, they are removed from the list in PopUps. Anyways, the list, once empty, throws a ConcurrentModificationException. I don't know what to do to fix this, so I brought the question here.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
   /**
    * Render all popups
    */

   public void render(){
     
      for(PopUp popup : popups){ // This line is where the exception is thrown.
         if(popup.isDisposed()){
            popups.remove(popup);
            continue;
         }
         popup.render();
      }
     
   }


Any thoughts? If you need to see more code just ask Smiley

CopyableCougar4

Either wandering the forum or programming. Most likely the latter Smiley

Github: http://github.com/CopyableCougar4
Online Longarmx
« Reply #1 - Posted 2014-06-24 23:23:34 »

You can't use a for each loop if you add or remove items. You have to instead loop through backwards with a regular for loop.

1  
2  
3  
4  
5  
6  
7  
8  
9  
for(int i = popups.size() - 1; i >= 0; i--)
{
     Popup popup = popups.get(i);
     if(popup.isDisposed()){
            popups.remove(popup);
            continue;
     }
     popup.render();
}

Offline CopyableCougar4
« Reply #2 - Posted 2014-06-24 23:24:36 »

Hi

Thanks Longarmx Smiley

CopyableCougar4

Either wandering the forum or programming. Most likely the latter Smiley

Github: http://github.com/CopyableCougar4
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline GoToLoop

Junior Devvie


Medals: 2
Exp: 1 year



« Reply #3 - Posted 2014-06-24 23:46:28 »

I prefer this slightly more compact format using the faster overloaded index-based version of the remove() method:   Roll Eyes

1  
2  
3  
4  
5  
6  
for (int i = popups.size(); i-- != 0;) {
  PopUp p = popups.get(i);

  if (p.isDisposed())  popups.remove(i);
  else                 p.render();
}


And in the case the index order isn't important, this approach averts any left-shifting after remove(): Grin

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
for (int len = popups.size(), i = len; i-- != 0;) {
  PopUp p = popups.get(i);

  if (!p.isDisposed())  p.render();

  else {
    p = popups.remove(--len);
    if (i != len)  popups.set(i, p);
  }
}
Offline PocketCrafter7

Senior Devvie


Medals: 6
Projects: 2
Exp: 2 years


One man's bug is another man's feature


« Reply #4 - Posted 2014-06-25 06:53:13 »

For removing you can use this as well:

1  
2  
3  
4  
5  
6  
7  
8  
9  
for (int i = 0; i < popups.size(); i++) {
       Popup p = popups.get (i);

       if (p.isDisposed ()) {
              popups.remove (i);
              i--;
       }
       p.render();
}

Nothing is difficult in this world. It is just how you look at it.
Offline PandaMoniumHUN

JGO Coder


Medals: 32
Exp: 3 years


White-bearded OGL wizard


« Reply #5 - Posted 2014-06-25 07:11:05 »

 Huh
I'm wondering why nobody has mentioned the 'best' method (most commonly used, fast and reliable): Use iterators.
With iterator's you can remove objects from a collection while you're iterating over them.
Sample:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
public void render(){
   Iterator<PopUp> iterator = popups.iterator();
   while(iterator.hasNext()){
      PopUp popup = iterator.next();
      if(popup.isDisposed()){
         iterator.remove();
         continue;
      }
      popup.render();
   }
}

You should loop until
iterator.hasNext()
, you can receive the current element with
iterator.next()
and delete the current element from the collection using
iterator.remove()
. Wink

My Blog | Jumpbutton Studio - INOP Programmer
Can't stress enough: Don't start game development until you haven't got the basics of programming down! Pointing
Offline GoToLoop

Junior Devvie


Medals: 2
Exp: 1 year



« Reply #6 - Posted 2014-06-25 07:36:55 »

I daresay that a backwards loop would still be a bit faster than an Iterator version.
B/c the condition is against a literal 0 rather than a method call like hasNext()!   persecutioncomplex
And the 2nd example using a remove()/set() combo is unbeatable! Averting left-shifting collateral is hard to ignore IMO!   Roll Eyes
On the other hand, if I was dealing w/ a structure like a LinkedList or similar, going w/ an Iterator or a ListIterator is a no-brainer!   Tongue
Offline PandaMoniumHUN

JGO Coder


Medals: 32
Exp: 3 years


White-bearded OGL wizard


« Reply #7 - Posted 2014-06-25 17:16:02 »

I daresay that a backwards loop would still be a bit faster than an Iterator version.
B/c the condition is against a literal 0 rather than a method call like hasNext()!   persecutioncomplex
Wrong. Java's built-in for-each loop essentially uses iterators so the performance is exactly the same, while the c-style for loop what you're talking about will generally be slower. You can read a pretty good explanation on that here. Smiley

My Blog | Jumpbutton Studio - INOP Programmer
Can't stress enough: Don't start game development until you haven't got the basics of programming down! Pointing
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 485
Exp: 7 years



« Reply #8 - Posted 2014-06-25 17:19:58 »

I see no evidence there that the c-style is slower for iterating over a random access structure such as ArrayList. Sure it will be night and day with a LinkedList, but that is a separate issue.
Offline Riven
Administrator

« JGO Overlord »


Medals: 1342
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #9 - Posted 2014-06-25 17:38:26 »

C-style is about 10% faster to iterate and doesn't create an Iterator instance that the GC has to cleanup.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings!
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 485
Exp: 7 years



« Reply #10 - Posted 2014-06-25 17:42:28 »

Indeed. Iterators in tight nested loops can actually put substantial pressure on the GC if you're not careful.
How recent is that 10% figure?
Offline Riven
Administrator

« JGO Overlord »


Medals: 1342
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #11 - Posted 2014-06-25 19:28:43 »

Java 7u42 or so.

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings!
Offline GoToLoop

Junior Devvie


Medals: 2
Exp: 1 year



« Reply #12 - Posted 2014-06-25 20:11:11 »

Don't get me wrong, I love using the "enhanced" for-"each" loop version!
Even though it can be 10% slower for non-array structures than a c-style for loop! Grin
However, we can't use remove() on such loops. Either c-style or Iterator/ListIterator style for such occasions!  Roll Eyes
Offline PandaMoniumHUN

JGO Coder


Medals: 32
Exp: 3 years


White-bearded OGL wizard


« Reply #13 - Posted 2014-06-25 22:42:12 »

Just written a minibenchmark for this and the result I got is kind of surprising.
No matter how many samples I use, or what array size, I always end up with iterators and c-style loops being almost exactly as fast, and for-each loops being quite a bit slower.
The results I've got from the gist above on an i5 3570K@4GHz, Win7, Java 7u60:
1  
2  
3  
4  
5  
Array size: 150000
Total time took: 2549ms or 2.549 seconds
Enhanced for average: 0.672
C for average: 0.53
Iterator average: 0.532


So as I see it, there is really no reason to avoid iterators if you're afraid of performance loss. If you prefer C-style for loops over iterators because that's your programming style though, that's a valid reason. Smiley
If there's anything wrong with my minibenchmark (can easily happen since I wrote it around 1AM) let me know please. Smiley

My Blog | Jumpbutton Studio - INOP Programmer
Can't stress enough: Don't start game development until you haven't got the basics of programming down! Pointing
Offline BurntPizza

« JGO Bitwise Duke »


Medals: 485
Exp: 7 years



« Reply #14 - Posted 2014-06-25 23:02:19 »

I made the loops in your bench actually perform work (minimal, incrementing a counter by the string length) and made it run the whole test over and over (to make sure the JIT is warmed, makes a difference):
It's still pretty impromptu though.

Results which are consistent after a few rounds: (upped samples because 500 is not much)
Quote
Number of samples: 5000
Array size: 150000
Enhanced for average: 1.953
C for average: 1.8866
Iterator average: 1.9416

Still odd that the for-each and iterators are different...

EDIT: this is on Win7, 7u51

8u5 results, in case it matters:
Quote
Number of samples: 5000
Array size: 150000
Enhanced for average: 1.8838
C for average: 1.8162
Iterator average: 1.8698

Tidy speed up there it seems.
Pages: [1]
  ignore  |  Print  
 
 

 
EgonOlsen (579 views)
2018-06-10 19:43:48

EgonOlsen (682 views)
2018-06-10 19:43:44

EgonOlsen (471 views)
2018-06-10 19:43:20

DesertCoockie (822 views)
2018-05-13 18:23:11

nelsongames (1025 views)
2018-04-24 18:15:36

nelsongames (1074 views)
2018-04-24 18:14:32

ivj94 (1654 views)
2018-03-24 14:47:39

ivj94 (582 views)
2018-03-24 14:46:31

ivj94 (1483 views)
2018-03-24 14:43:53

Solater (567 views)
2018-03-17 05:04:08
Deployment and Packaging
by philfrei
2018-08-20 02:33:38

Deployment and Packaging
by philfrei
2018-08-20 02:29:55

Deployment and Packaging
by philfrei
2018-08-19 23:56:20

Deployment and Packaging
by philfrei
2018-08-19 23:54:46

Deployment and Packaging
by philfrei
2018-08-19 23:53:08

Deployment and Packaging
by philfrei
2018-08-19 23:50:04

Java Gaming Resources
by philfrei
2017-12-05 19:38:37

Java Gaming Resources
by philfrei
2017-12-05 19:37:39
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!