java.util.ConcurrentModificationException in Android Game Loop - java

I am using a canvas, moving objects on the screen, when an object hit the left side of the canvas (x=0), another object of the same type gets instantiated, and start moving on the screen.
Everything works fine, a few objects gets created and start moving around the screen.
At a certain point, I receive a concurrent modification exception in my run method where the game loop is, where gameObjs is an ArrayList:
#Override
public void run() {
while(isRunning){
if(!myHolder.getSurface().isValid())
continue;
Canvas canvas = myHolder.lockCanvas();
canvas.drawRect(0,0,canvas.getWidth(), canvas.getHeight(), pWhite);
for(MyGameObject gameObj : gameObjs){
gameObj.move(canvas);
}
myHolder.unlockCanvasAndPost(canvas);
}
}
I've tried to use an Iterator, but still getting the same error.
I really appreciate your help. Thank you in advance!

Collections.synchronizedList(...) won't work if something like this is happening... (throws a ConcurrentModificationException...)
public class ConcurrentTest {
public static void main(String[] args) {
List<String> things = new ArrayList<>();
Runnable modifyThread = () -> {
while(true) {
for(int k = 0; k < 1000; k++) {
things.add(String.valueOf(k));
}
while(!things.isEmpty()) {
things.remove(0);
}
}
};
Runnable readThread = () -> {
while(true) {
for(String thing : Collections.synchronizedList(things)) {
System.out.println(thing);
}
}
};
new Thread(modifyThread).start();
new Thread(readThread).start();
}
}
Try and find other places in your code where this list is being modified. There must be another thread manipulating the collection while you are iterating through it.
You could take a copy of the list before iterating over it.
For example, in the code above, try...
for(String thing : new ArrayList<>(things)) {
...instead of...
for(String thing : Collections.synchronizedList(things)) {
...and you will no longer get an exception (but this still won't be "correct", if you run it, you will see loads of nulls being printed out...)
Even better, keep the read loop as...
for(String thing : things) {
...but change the type of list...
List<String> things = new CopyOnWriteArrayList<>();

Related

Java filter works with one predicate but not with another

Help! This doesn't make the slightest kind of sense.
I have a Java Collection and a method that filters this collection.
public void filter(Predicate<? super T> predicate) {
for (MyItem<T> item=head; item!=null; item=item.next) {
if(predicate.test(item.key))
remove(item.key);
item = item.next;
}
}
Then, when I run it with one predicate, it works.
public static void main(String[] args) {
MySet<Integer> set = new MySet<>();
for(int i=0; i<20; i++) {
set.add(i);
}
set.filter(x->x%2==0);
MyItem<Integer> item = set.head;
for(int i=0; i<10; i++) {
System.out.println(item.key);
item = item.next;
}
}
It correctly outputs all the uneven numbers from 1 to 19.
If I change the predicate to x->x%2==1, however, it doesn't output all the even numbers from 0 to 18, it outputs all numbers from 0 to 9.
Why is this even possible???
Thanks in advance!
You have 2 times item=item.next, once in the for loop declaration and once inside. So you skip half of the items.
for (MyItem<T> item=head; item!=null; item=item.next) {
if(predicate.test(item.key))
remove(item.key);
// item = item.next; ???
}
The problem most likely comes from the fact that you skip every second element in your loop inside of filter method. You call item = item.next twice in there, as an "increment" of the loop (3rd part of the loop definition) and then at the end of each iteration.
public void filter(Predicate<? super T> predicate) {
for (MyItem<T> item=head; item!=null; item=item.next) { //<- here
if(predicate.test(item.key))
remove(item.key);
item = item.next; //<- here
}
}
Remove either of those, preferably in the last line, and it should work fine.

Static array declared but method cannot work

I have to do my homework in Greenfoot.
This part means that I have to save the position of Chess and then click reset.
Then, I have to choose load to put back the pieces of chess in the position they had before reset.
Since I don't know the exact size of the array, I know I can use List but it isn't allowed in the homework.
Nothing showed up on the screen but there is no error message.
Assume I have a class called Chess.
static Actor[] allChess;
public void save() // this is the save
{
Actor[] allChess = GWorld.getAllObjects("Chess");
}
public void load() // this is the load
{
if (allChess != null)
{
for (int i=0; i < allChess.length; i++)
{
Chess ch = (Chess) allChess[i];
GWorld.addOneObject(new Chess(ch.color, ch.rank), ch.getX(), ch.getY());
}
}
}
Thanks a lot!
allChess is redeclared as a local variable in save(). Do like this :
public void save() // this is the save
{
allChess = GWorld.getAllObjects("Chess");
}

Loop through array of objects inside the class

I am having some trouble looping through an array with objects, inside the class. I wrote a little demo here so you can follow:
Tank tanks[] = new Tank[2];
tanks[0] = new Tank();
tanks[1] = new Tank();
tanks[0].doStuff(tanks);
doStuff(Tank[] tanks) {
for (int i = 0; i < tanks.length; i++) {
if (tanks[i].equals(this)) continue;
// Do stuff
}
}
So, I have an array with the type Tank. Then I call the method doStuff inside the Tank class. The method takes the array and loops through it. And then I want to do stuff to every tank that is not the current instance of the class. I hope you can make sense out of my code and this description.
The problem is that I get nullPointerException for if (tanks[i].equals(this))
What am I doing wrong here?
That means that tanks[i] is null. (or that your overridden equals() method has a bug)
You need to check for that.
if you want to compare the IDs of your object you can use == instead of .equals()
doStuff(Tank tanks) {
for (int i = 0; i < tanks.length; i++) {
if (tanks[i] == this) {
continue;
}
// Do stuff
}
}
When I run this code:
public class Tank {
public static void main(String[] args) {
Tank tanks[] = new Tank[2];
tanks[0] = new Tank();
tanks[1] = new Tank();
tanks[0].doStuff(tanks);
}
public void doStuff(Tank[] tanks) {
for (int i = 0; i < tanks.length; i++) {
if (tanks[i].equals(this)) continue;
// Do stuff
}
}
}
No error happens. Therefore, you've probably overridden .equals, and that is where the NullPointerException is occurring. The other possibility is that your simple example doesn't accurately reflect where your bug is occurring.

in Java, how to traverse a queue without destroying it, in a simple way?

E.g.
I have a queue
void someMethod() {
history.add(new Sample(time, data));
...
traverse(history);
}
void traverse(Queue<Sample> history) {
for(int i=0; i<history.size(); i=i+10) {
history.get(i)... // ???
}
}
class Sample {
long time;
double data;
}
The concerns are that
I don't want to destroy this queue by calling traverse().
Traverse the queue in a given step, say 10 here.
Any simple and nice solution?
for (Sample s : history)
doStuff(s);
This is called the enhanced for-loop; you can read more about it here.
Queue implements Iterable, so a simple loop will traverse it:
for (Sample sample : history)
An Iterator is another way to do it, with more control (can destroy it if you want to), but more verbose.
If you just want to iterate, use a for-each loop or directly a for loop with an Iterator. This doesn't consume the queue.
If you need to iterate with a step, you can use this pattern. It works generally with any Iterable. Putting the skipping into a separate reusable method makes the code more clear than having two nested for loops.
public static void main(String[] args) {
Queue<Sample> history = ...
int step = 10;
for (Iterator<Sample> it = history.iterator();
it.hasNext(); skip(it, step - 1)) {
// note that we skipped 1 less elements than the size of the step
Sample sample = it.next();
// stuff
}
}
static void skip(Iterator<?> iterator, int count) {
for (int i = 0; i < count && iterator.hasNext(); i++) {
iterator.next();
}
}
LinkedList<Sample> h = (LinkedList<Sample>) history;
for(int i=0; i < h.size(); i+=step) {
h.get(i).memory ...
}
I just realized this approach, haven't tried it yet.
As nullptr pointed out, the condition for above code is that the Queue is implemented as a LinkedList. (which is my case: Queue<Sample> history = new LinkedList<Sample>();)

ConcurrentModificationException for Java LinkedList

I have LinkedList of objects and an iterator. I know that this ConcurrentModificationException is thrown when you try to modify the list while running the iterator. But in my case, I don't understand where this modification is being done.
The iterator looks like this :
private static void insertTasks(Task t) {
if(eventQueue.size() == 0) {
eventQueue.addFirst(tsk);
return;
}
int pos = 0;
while (itr.hasNext()){
//The line below throws the exception
if (t.getArrivalTime() <= itr.next().getArrivalTime() )
{
break;
}
pos++;
}
}
I am calling this insertTasks method from another method as shown below :
tsk = null;
tsk = new Task(1,"P1",1,4.0f,1.5f,0.0f,8.0f);
insertTasks(tsk);
tsk = null;
tsk = new Task(0,"P0",2,5.0f,2.5f,1.0f,10.0f);
insertTasks(tsk);
The getArrivalTime in the Task objects looks like :
public float getArrivalTime() { return arrivalTime; }
My question is, where am I doing this modification ? The while loop where I run this iterator is not doing any modification. Does it ?
Am I missing something ?
I reckon the problem is that itr is a static field in your class and that's creating the issue, as you're adding an element to eventQueue in your second call to insertTasks().
Avoid static fields... program yourself to fear them and avoid them as much as you can :). They evil, and OO unfriendly.

Categories

Resources