Java ArrayList Remove. Synchronize?

Started by
10 comments, last by noodleBowl 8 years, 9 months ago

I got a quick question about ArrayLists

I have 2 ArrayLists, one for active TouchPoints and one for inactive TouchPoints.
In an Event Listener, When a finger is pressed on the screen the first object in my inactive list is moved over to my active list.


 
public void TouchPointDown()
{
	TouchPoint o = inactiveTouchPoint.get(0);
	o.Revive();
	
	activeTouchPoint.add(b);
	inactiveTouchPoint.remove(b);
}
 

Now when a finger is removed from the screen, I do the reverse. I remove the TouchPoint from the active list and move it back over to the inactive list.


 
public void MakeTouchPointInactive(int index)
{
	TouchPoint o = activeTouchPoint.get(index);
	o.Kill();

	inactiveTouchPoint.add(b);	
	activeTouchPoint.remove(b);

}
 

Now I think I have a problem here right?

If I am looping through my list of active TouchPoints and updating/checking them. I have the potential to throw an exception, because it would be possible to be in the middle of updating/checking the active TouchPoints, but then at the same time the Listener could be triggered by removing a finger from the screen. Causing a TouchPoint to be removed from the active list, and then my loop explodes on being out of bounds because I'm still tyring to update/check my active TouchPoints.

How can I stop this? What is the best solution?

Could I just loop through my array list backwards? Does this call for the synchronized keyword?

Also can someone explain to me what the synchronize keyword actually does?

I understand its like a semaphore, but what happens if something already has the lock? Does the syncronized code section get skipped over or do I block until the lock becomes available?

Advertisement

If you use a thread-safe collection then these race conditions won't happen.

http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html

It looks like this:



List<Type> list = Collections.synchronizedList(new ArrayList<Type>());

// these methods are thread safe now
list.add()
list.remove()
list.size()
etc...

// just make sure to iterate only when you hold the lock

synchronized( list ) { // <- this must be done when looping the list
   for( Type type : list ) {
      ...
   }
}


You should really read more about threads. https://docs.oracle.com/javase/tutorial/essential/concurrency/simple.html

As for what synchronized methods do, they are just like having a synchronized block on the 'this' keyword:


pubic class A {

   public synchronized void b() {
      // only one thread at a time
      code...
   }

   public void c() {
      // this is the same as b()
      synchronized( this ) {
         code...
      }
   }
}

I think, therefore I am. I think? - "George Carlin"
My Website: Indie Game Programming

My Twitter: https://twitter.com/indieprogram

My Book: http://amzn.com/1305076532

If you use a thread-safe collection then these race conditions won't happen.

http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html


Didn't know this existed, good to know.

So I have a follow up question. And this is open to anyone

Do you think these active/inactive lists are a good idea?
Would it be better to just have X amount of TouchPoint objects in a single list and just mark them as active/inactive as needed?
The only thing is that I would have to loop through all the objects to figure out which ones are active


public void TouchPointDown()
{
	for(int i = 0; i < touchPointList.size(); ++i)
	{
		TouchPoint o = touchPointList.get(i);
		if(o.isActive == false)
		{
			o.Revive(); //Gets IsActive set to true
			break;
		}
	}
}

public void TouchPointUp(int touchPointID)
{
	for(int i = 0; i < touchPointList.size(); ++i)
	{
		TouchPoint o = touchPointList.get(i);
		if(o.ID == touchPointID)
		{
			o.Kill(); //Gets IsActive set to false
			break;
		}
	}
}
Maybe a HashMap is better suited? Although I really don't like the idea of having to create an iterator just to traverse through the map

Anyway thoughts?

It seems to me that you're doing "premature optimization" trying to reuse these, but is this really causing any speed problems? I try to write the dumbest thing I can everywhere, so that when I finally do need to speed something up, it's simple enough that I can refactor/optimize it without breaking other stuff.

I would just have one list. When a touch point is down, add it to the list. When it's up, remove it.

I think, therefore I am. I think? - "George Carlin"
My Website: Indie Game Programming

My Twitter: https://twitter.com/indieprogram

My Book: http://amzn.com/1305076532

I would just have one list. When a touch point is down, add it to the list. When it's up, remove it.

Wouldn't I just run into my original problem then? Since the touch listener is executed on a separate thread?

I always cringe when I see a loop iterating over a collection in synchronized block because it's often a place where deadlocks are lurking. It might be OK, it's probably OK, but I've been burned too many times before. Also, if processing the list takes any length of time (unlikely in a tight game loop, but still) then your UI thread could be blocked waiting for the chance to add/remove an item.

In this case I would highly recommend the CopyOnWriteArrayList (in the java.util.concurrent package). Unlike ArrayList, the class itself is thread-safe so you don't need to be burdened with figuring out where to put the synchronized keyword. In particular, you can iterate over the contents of the list (using an Iterator) without needing to hold a lock the entire time. This means your game thread can be processing touch points at the same time that you're adding/removing points on the UI thread.

This means your game thread can be processing touch points at the same time that you're adding/removing points on the UI thread.


Because I know nothing, please correct me

If I have a class that implements some Listener, does this automatically get thrown into its own thread? or

EG:
public class MainClass
{
	
	public TouchListenerObject myTouchListner = new TouchListenerObject(); // Creates a new listener. Automatically gets pushed to its own thread?
	public static void main(String [] args)
	{
                while(true)
                {
                   myTouchListener.CheckOnTouchPoints();
		   /* Do other main stuff */
                }
	}

}
If that is the case would it just be better to pass data to the thread, then the other way around?

Basically, for example, instead of getting all the active touch points and checking if one is in some hixbox for a button.
The hitbox is passed to the listener object and each object checks if its' self is in the hixbox

hitbox.ContainsPoint(currentPoint) vs touchPoint.IsInside(hitbox)

I always cringe when I see a loop iterating over a collection in synchronized block because it's often a place where deadlocks are lurking. It might be OK, it's probably OK, but I've been burned too many times before. Also, if processing the list takes any length of time (unlikely in a tight game loop, but still) then your UI thread could be blocked waiting for the chance to add/remove an item.


I'm also wondering how this could cause a dead lock? I mean the loop will finish, if it was a while loop I could see it, but this one I'm not sure. I'm curious because I have not done a lot of multi threaded programming before

Edit: Totally thought I was editing my previous post smile.png Sorry

I think the fear is that if the code iterating over the collection calls some other code that needs to add another item to the list, it can't, because this class has a lock. But since the lock is re-entrant, I don't see how that can happen.

So I'm not sure how it can deadlock either. I was trying to figure it out, but I can't come up with anything.

I think, therefore I am. I think? - "George Carlin"
My Website: Indie Game Programming

My Twitter: https://twitter.com/indieprogram

My Book: http://amzn.com/1305076532

I'd use an ArrayBlockingQueue instead.

Producer (whatever generates your input events) puts stuff in, consumer (whatever translates events into actions) consumes the stuff you put in there. Straightforward enough.

"I AM ZE EMPRAH OPENGL 3.3 THE CORE, I DEMAND FROM THEE ZE SHADERZ AND MATRIXEZ"

My journals: dustArtemis ECS framework and Making a Terrain Generator

This topic is closed to new replies.

Advertisement