ArrayList.add () ArrayIndexOutOfBoundsException processing

3

I have searched on this page but I can not find a solution. I have the following code:

class BodyThread extends Thread {
private Thread t;
private String threadName;
private boolean isCreature;
ArrayList<Creature> creatures;
ArrayList<DeadBody> bodies;
double timeStep;

public BodyThread(String name, ArrayList array, double ts, boolean ic/*, Boolean uc*/) {
  threadName = name;
  timeStep = ts;
  isCreature = ic;
  if(ic) creatures = array;
  else bodies = array;
}
public void run() {
  if(isCreature){
    for(int i = 0; i<creatures.size(); i++){
      creatures.get(i).collide(timeStep);
      creatures.get(i).metabolize(timeStep);
      creatures.get(i).useBrain(timeStep/*, !userControl*/);
      if(creatures.get(i).getRadius() < creatures.get(i).board.MINIMUM_SURVIVABLE_SIZE){
        creatures.get(i).returnToEarth();
        creatures.remove(creatures.get(i));
        i--;
        return;
      }       
    }
    for(int i = 0; i<creatures.size(); i++){
      Creature cr = creatures.get(i);
     creatures.get(i).applyMotions(timeStep*cr.board.OBJECT_TIMESTEPS_PER_YEAR);
     creatures.get(i).see(timeStep*cr.board.OBJECT_TIMESTEPS_PER_YEAR);
    }   
  }else{
    for(int i = 0; i<bodies.size(); i++){
      bodies.get(i).collide(timeStep);
      bodies.get(i).decay(timeStep);
      if(bodies.get(i).getRadius() <= 0){
        bodies.remove(bodies.get(i));
        i--;
        return;
      }
    }
    for(int i = 0; i<bodies.size(); i++) bodies.get(i).applyMotions(timeStep*bodies.get(i).board.OBJECT_TIMESTEPS_PER_YEAR);
  }  
}

public void start () {
  if (t == null) {
     t = new Thread (this, threadName);
     t.start ();
    }
  }
}
class SoftBody{
double px;
double py;
double vx;
double vy;
double energy;
float ENERGY_DENSITY; 
double density;
double hue;
double saturation;
double brightness;
double birthTime;
boolean isCreature = false;
final float FRICTION = 0.004;
final float COLLISION_FORCE = 0.01;
final float FIGHT_RANGE = 2.0;
double fightLevel = 0;
ArrayList<SoftBody> colliders;
Board board;

public void collide(double timeStep){
  colliders = new ArrayList<SoftBody>(0);
  for(int x = SBIPMinX; x <= SBIPMaxX; x++){
    for(int y = SBIPMinY; y <= SBIPMaxY; y++){
      for(int i = 0; i < board.softBodiesInPositions[x][y].size(); i++){
        SoftBody newCollider = (SoftBody)board.softBodiesInPositions[x][y].get(i);
        if(!colliders.contains(newCollider) && newCollider != this){
          colliders.add(newCollider); //ArrayIndexOutOfBoundsException
        }
      }
    }
  }
  for(int i = 0; i < colliders.size(); i++){
    SoftBody collider = colliders.get(i);
    float distance = dist((float)px,(float)py,(float)collider.px,(float)collider.py);
    double combinedRadius = getRadius()+collider.getRadius();
    if(distance < combinedRadius){
      double force = combinedRadius*COLLISION_FORCE;
      vx += ((px-collider.px)/distance)*force/getMass();
      vy += ((py-collider.py)/distance)*force/getMass();
    }
  }
  fightLevel = 0;
}
}
class Board{
  void iterate(){// I'll just put the part where I run the thread.
    creaturesThread = new BodyThread("Creature Thread", creatures, timeStep, true);
    bodiesThread = new BodyThread("Bodies Thread", bodies, timeStep, false);
    creaturesThread.start();
    bodiesThread.start();
    try{
      creaturesThread.join();
      bodiesThread.join();
    }catch (Exception e) {
      System.out.println(e);
}
}

(This is only the important part of the code). As far as I know, the get function should not give an error. I would like to know what I can do to prevent this from happening. Thanks.

    
asked by joroba3 01.12.2016 в 19:50
source

2 answers

2

Most likely, your problem is a race condition, because you access a list with threads that is not synchronized (not secure in thread / not thread safe).

Internally the ArrayList#add(Object o) method measures the size of the list and then adds the element to the size() position (which is the last index plus one).

If between measuring the current size and adding the element passes a size reduction by remove , an exception ArrayIndexOutOfBounds is caused.

A solution to your problem may be to synchronize the code in which you add and remove objects from the list, or use a CopyOnWriteArrayList , to avoid this problem.

Probably the easiest way (not necessarily the best) is to synchronize the ArrayList using Collections :

List<Creatures> creatures = Collections.synchronizedList(new ArrayList<Creatures>());
    
answered by 31.03.2017 в 02:22
-2

In this case, the ArrayList is correctly defined:

 colliders = new ArrayList<SoftBody>(0);

The error ArrayIndexOutOfBoundsException can happen when you add an element to your ArrayList that at some point newCollider has a null value:

 colliders.add(newCollider);

I explain it to you with this image, if you add to your ArrayList an element with value null , this example on 8 (index 7), the measure of your ArrayList is the one of the elements that you added but in reality only you can check 9 since one contains a null value.

Another cause may be that your ArrayList is being modified by another Thread.

    
answered by 01.12.2016 в 20:18