Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (106)
games submitted by our members
Games in WIP (533)
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  
  Concurrency.. ^^  (Read 4117 times)
0 Members and 1 Guest are viewing this topic.
Offline Regenuluz
« Posted 2012-04-09 20:29:54 »

'ello folks,

So I'm storing a LinkedList of entities that does stuff every tick, however this list is modified in a different thread than the thread that loops through it and ticks the entities it holds.

Now as you might've guessed, this is causing ConcurrentModificationExceptions to be thrown left and right! Now, I'd really like to know how the heck I can avoid this problem?
Offline teletubo
« League of Dukes »

JGO Ninja


Medals: 48
Projects: 4
Exp: 8 years



« Reply #1 - Posted 2012-04-09 20:35:36 »

well just don't access it from different Threads!
You will not only avoid this exception but as well as many other concurrency problems you might face.

But if you really insist on multi threading, take a look at ConcurrentLinkedQueue class.

Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #2 - Posted 2012-04-09 20:41:04 »

Vectors could help you, because they're syncronized. The rest of the Collections are not.
Also, the volatile keyword makes sure the field is never stored Thread locally, and access is always as if it's through a syncronized block. Smiley

This should make it Thread-safe.

Edit: Proven wrong.  Clueless

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline cylab

JGO Ninja


Medals: 38



« Reply #3 - Posted 2012-04-09 20:48:29 »

This should make it Thread-safe.
Nope http://stackoverflow.com/questions/9059266/does-volatile-mean-it-is-thread-safe

Mathias - I Know What [you] Did Last Summer!
Offline Regenuluz
« Reply #4 - Posted 2012-04-09 20:49:27 »

@Teletubo That's a little hard, since one thread is the one handling all my input(That would be the swing one, I suppose) and the other is the one handling the game loop. I might end up using that ConcurrentLinkedQueue, though I don't like that the size() function runs in O(n) instead of constant time.

@Mads According to the javadocs, then vectors aren't going to help me. They'll throw ConcurrentModificationExceptions too, if I try to edit them while iteration through them. Smiley
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #5 - Posted 2012-04-09 20:50:45 »

Vectors could help you, because they're syncronized. The rest of the Collections are not.

The proper way to do it is to use Collections.synchronizedList (or synchronizedMap, etc.) rather than using Vector. Or as teletubo mentions use the collections in java.util.concurrent.*

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline cylab

JGO Ninja


Medals: 38



« Reply #6 - Posted 2012-04-09 20:57:10 »

@Regenuluz
I usually solve this by stuffing Events/Actions/Whatever on non-gameloop-threads into a ConcurrentLinkedQueue and retrieve them for processing in the gameloop-thread. This way you can use whatever collections you want in the gameloop and schedule thread safe modifications from outside.

Mathias - I Know What [you] Did Last Summer!
Offline princec

JGO Kernel


Medals: 342
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #7 - Posted 2012-04-09 21:01:06 »

synchronized won't fix concurrent modification problems which are what happens when one thread is iterating and one thread starts changing stuff in the list.

Do this:

1. Stop using LinkedLists anyway. Use ArrayLists.
2. Stop using two threads. Do everything in one thread that needs to be done to that list.

Cas Smiley

Offline Regenuluz
« Reply #8 - Posted 2012-04-09 21:07:58 »

Well, this:

1  
public List<Entity> entitiesToTick = Collections.synchronizedList(new LinkedList<Entity>());


plus this:

1  
2  
3  
4  
5  
synchronized (entitiesToTick) {
   for (Entity e : entitiesToTick) {
      e.tick();
   }
}


fixed it, or at least I haven't gotten a single ConcurrentModificationException yet, after using that. Smiley

Thanks for the help guys! Cheesy


P.S.:
And now that I know all you clever people are around, go answer my other question! I still haven't solved that one! Cry (This one: http://www.java-gaming.org/topics/making-stuff-work-between-windows-and-osx/26132/view.html Tongue)
Offline Regenuluz
« Reply #9 - Posted 2012-04-09 21:21:46 »

Actually, on a side node:

Quote
1. Stop using LinkedLists anyway. Use ArrayLists.

Why?
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline sproingie

JGO Kernel


Medals: 201



« Reply #10 - Posted 2012-04-09 21:29:20 »

ArrayLists are faster for most uses.  Even ones where LinkedList has a better complexity, ArrayList tends to outrun it for small lists simply because the array operations are so much faster than chasing pointers.  If you need to do a lot of insertion and removal at the ends, ArrayDeque is a good choice.

Doubtful you'll see much difference though until you start pressuring the gc, at which point you will appreciate the difference.
Offline pitbuller
« Reply #11 - Posted 2012-04-09 22:24:41 »

Well, this:

1  
public List<Entity> entitiesToTick = Collections.synchronizedList(new LinkedList<Entity>());


plus this:

1  
2  
3  
4  
5  
synchronized (entitiesToTick) {
   for (Entity e : entitiesToTick) {
      e.tick();
   }
}


fixed it, or at least I haven't gotten a single ConcurrentModificationException yet, after using that. Smiley

Thats not how you design against concurrency. You just can't test it a while and say its solved. You need to analyze it a bit more than do a couple test run.
Offline sproingie

JGO Kernel


Medals: 201



« Reply #12 - Posted 2012-04-10 00:16:30 »

The design looks sound to me.  It'll run through the whole list, and any threads spawned that try to modify entitiesToTick will block until the loop is done telling everything in the list to tick.  As long as tick() methods don't block, it looks reasonable.

Offline princec

JGO Kernel


Medals: 342
Projects: 3
Exp: 16 years


Eh? Who? What? ... Me?


« Reply #13 - Posted 2012-04-10 00:48:49 »

Indeed that will work but effectively single threading the use of the list rather looks like it defeats the purpose of having another thread manipulating it I think.

Cas Smiley

Offline loom_weaver

JGO Coder


Medals: 17



« Reply #14 - Posted 2012-04-10 02:24:53 »

Another question to ask yourself is why exactly are you using threads?

Newbie and concurrency do not go together.  I guess this can be a learning experience but dang...
Offline sproingie

JGO Kernel


Medals: 201



« Reply #15 - Posted 2012-04-10 03:37:46 »

Indeed that will work but effectively single threading the use of the list rather looks like it defeats the purpose of having another thread manipulating it I think.

Naw, it will fire off all the tick() events quickly then finish.  As long as tick() is cheap, the loop shouldn't block anything else for too long.  Personally, I wouldn't share the list at all, thus obviating the need to lock it, but locking it just long enough to fire off a bunch of tick events seems reasonable.

I would agree you should have a strong justification for using threads before pulling them out though, or your concurrency constructs should make them invisible to you.


Offline Regenuluz
« Reply #16 - Posted 2012-04-10 08:09:49 »

Quote
You need to analyze it a bit more than do a couple test run.
^ I did give it a couple of test runs.


Well, what I'm doing in my constructor is:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
public MapEditor() {
   this.mainWindow = new MainWindow(this);
   this.setFocusable(true);
   this.requestFocus();

   // Show loading screen
  this.screen = new LoadingScreen(this);

   // Fire up under the painting!
  new Thread(this).start();

   // Initialize map data
  init();

   // Add controllers
  this.addKeyListener(new KeyController(this));
   MouseController mc = new MouseController(this);
   this.addMouseListener(mc);
   this.addMouseMotionListener(mc);
}


I've tried shuffling it around a bit, but I have no idea how to avoid the exception, except for doing it like I posted a little earlier. So how would I go on about making this single threaded..?
Offline sproingie

JGO Kernel


Medals: 201



« Reply #17 - Posted 2012-04-10 19:11:15 »

Quote
You need to analyze it a bit more than do a couple test run.
^ I did give it a couple of test runs.

You need to read that more closely.  He said you need to do more than a couple test runs, and his point was that you need to understand what it's doing, and why it works.  For example, synchronizing on the list reference itself will only protect you from CME if everything else synchronizes on the same thing.  Are you sure that's what the list's own methods synchronize on?  Not everything in the standard library uses synchronized(this), some things create an internal lock and synchronize on that.

Your code happens to work, but if you don't know why, it's bound to break with the slightest change.

Offline Regenuluz
« Reply #18 - Posted 2012-04-10 20:18:21 »

Arh right. Well, as far as I've understood from the java docs, then the linked list doesn't do any synch'ing, in which case it shouldn't pose a problem as long as I remember to sync it myself.

Or am I entirely off the mark here? (If that's the case, please do explain ^^)
Offline sproingie

JGO Kernel


Medals: 201



« Reply #19 - Posted 2012-04-10 20:28:02 »

If you synchronize all access to it yourself, you're perfectly ok.  It's just when you use concurrent collections and mix the internally-synchronized methods with your own synchronization where you can screw the pooch.  I speak from experience, poor pooch.
Offline Mads

JGO Ninja


Medals: 26
Projects: 3
Exp: 6 years


One for all!


« Reply #20 - Posted 2012-04-11 04:31:15 »

What if you just use a for loop instead, and check for null objects? Would that not (although while being a cheap solution), stop throwing you those exceptions?  Smiley

Offline Regenuluz
« Reply #21 - Posted 2012-04-11 10:18:41 »

@sproingie
Arh, well, I am synch'ing it myself Smiley But I'll make a note to remember to not mix concurrent collections and internally-synch'ed methods. Smiley

@Mads
It's not null pointers that's causing that exception. Smiley It's because elements are being added or removed from the list while it's being iterated through. ^_^
Offline cylab

JGO Ninja


Medals: 38



« Reply #22 - Posted 2012-04-11 10:55:18 »

@Mads
It's not null pointers that's causing that exception. Smiley It's because elements are being added or removed from the list while it's being iterated through. ^_^

He means a for-loop with an index and a getter. The CME is only thrown when using for(x:y) loops or Iterators. So his suggestion is

1  
2  
3  
4  
5  
for(int i=0; i<entitiesToTick.size(); i++)
{
    Entity e=entitiesToTick.get(i);
    if(e!=null) e.tick();
}


unfortunately that won't work either, because of:

Quote
public Object get(int index)

    Returns the element at the specified position in this list.

    Parameters:
        index - index of element to return.
    Returns:
        the element at the specified position in this list.
    Throws:
        IndexOutOfBoundsException - if the index is out of range (index < 0 || index >= size()).

so if an element gets removed while iterating over it, an IOOBE is thrown. Other than that, this loop could lead to missed entities or double calls to tick() on the same entity.

Mathias - I Know What [you] Did Last Summer!
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

pw (24 views)
2014-07-24 01:59:36

Riven (24 views)
2014-07-23 21:16:32

Riven (18 views)
2014-07-23 21:07:15

Riven (21 views)
2014-07-23 20:56:16

ctomni231 (50 views)
2014-07-18 06:55:21

Zero Volt (45 views)
2014-07-17 23:47:54

danieldean (36 views)
2014-07-17 23:41:23

MustardPeter (39 views)
2014-07-16 23:30:00

Cero (55 views)
2014-07-16 00:42:17

Riven (55 views)
2014-07-14 18:02:53
HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54

HotSpot Options
by Roquen
2014-05-06 15:03:10

Escape Analysis
by Roquen
2014-04-29 22:16:43

Experimental Toys
by Roquen
2014-04-28 13:24:22
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!