-3

I've run into a problem in which java is interpreting my code completely wrong and I don't know how to change that. Since my program is too complicated to really explain I'm going to give a generalized description of my problem and hope you are able to give me a generalized answer. In my code there is something along the lines of this:

function1();
object.function2();
function1();

function1 alters the object.

When I run this I get an exception while it's inside function2 (meaning the code never gets to the third line). However when I remove the third line, the code runs without any problems. This means that the java compiler is compiling my code in such a way that the second call of function1 has some influence on the previous line in which object.function2 is called. What is also interesting is that if you insert a breakpoint between line 2 and 3, it always works while debugging.

Is this normal? Is there any principle in java that is causing this, and any way to stop this? The code is available at this Bitbucket Repository, but be warned, it is undocumented spaghetti code and probably goes against every convention in java code. The problem described is inside Pool.java starting with line 41.

I hope the little information I've given here is sufficient for some kind of explanation.

MrQweep
  • 13
  • 3
  • post the code inside funtion1().... and tell me what is object for a type – ΦXocę 웃 Пepeúpa ツ Nov 13 '16 at 19:46
  • The content of those methods is relevant to the question, you need to give more information. E.g. what exception? – Luke Joshua Park Nov 13 '16 at 19:46
  • Well, if the code is that complex, perhaps you need to spend some time simplifying it. I highly doubt the problem is with the JVM. – Joe C Nov 13 '16 at 19:48
  • Added source code, though if you look at it you will understand why I initially didn't poste it. – MrQweep Nov 13 '16 at 20:08
  • That source link is not working, since the repository is not public. As it appears you are doing some multithreaded stuff, you might want to read https://www.cs.umd.edu/~pugh/java/memoryModel/jsr133.pdf (especially 8.1). The jave compiler is allowed to, and may do some optimisations to your code, that will, if you do not synchronize shared objects properly, lead to strange behaviour. – Aracurunir Nov 13 '16 at 20:17
  • Thanks, I checked by loading it in a private window, but i was still logged in, so I didn't notice. I am not asking java to do any multithreading, but I do not know much about java so i assumed it might automatically do that and thus cause this problem, since I have read multithreading does that sort of thing while trying to troubleshoot on my own. – MrQweep Nov 13 '16 at 20:27
  • I tried the code from your bitbucket repo, just running the main in "NEAT" works fine for me. – Aracurunir Nov 13 '16 at 20:55
  • Since it's a genetic algorithm, some randomness is involved; some conditions have to be met to cause the crash, which means you might have to run it multiple times before you experience the exception.(to increase the chance of the needed mutation, increase the amount of times the for loop inside epoch() is run.) – MrQweep Nov 13 '16 at 21:21

1 Answers1

0

Alright, I think to have figured this out enough, to be able to create an answer that might help you (for sure) and hopefully other people.

There is indeed multithreading involved, because

object.function2();

is creating a JFrame f. All drawing operations inside that frame f are executed by an AWT-EventQueue-0 (or any other number) task T. This task T is run parallel to your main thread M. Meaning every datastructure l (like a list) that is drawn in a custom JPanel p inside f and altered by M will potentially cause problems.

Example

public static void main(String[] args) {
    List<Integer> l = new ArrayList<Integer>(5);
    JFrame gui = new JFrame();
    gui.add(new MyPanel());
    l.add(10);
}

public class GUI extends JPanel {
    private List<Integer> l;
    public MyPanel(List<Integer> l) {
        this.l = l;
    }
    @Override
    public void paintComponent(Graphics g) { // this is called by JFrame.paint()
        super.paintComponent(g);
        List<Integer> modifiedL = new ArrayList<Integer>(l.size());
        for(Integer i : l) {
            modifiedL.add(2 * i);
        }
        // this is a stupid example, because it makes no sense to 
        // use this loop with l.size() here, but it shows the main problem. 
        for(int c = 0; c < l.size(); c++) { 
             somehowDrawSthWith(modifiedL.get(c));
        }
    }
}

By now changing the size of l after making the call to create the JFrame we cause an ArrayOutOfBoundsException when trying to access modifiedL.get(5), because the modifiedList may be created before l.add(10).

(A possible) Solution Note that I wrote possible, because this is hacky and just be avoided if possible. We need the Main thread M to wait until everything is painted. Here is a way to do this: Java wait for JFrame to finish In our example we would can change the main to:

public static void main(String[] args) {
    List<Integer> l = new ArrayList<Integer>(5);
    CountDownLatch jFrameDrawing = new CountDownLatch(1);
    JFrame gui = new JFrame();
    gui.add(new MyPanel(), jFrameDrawing); // add the counter
    try {
        jFrameDrawing.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    l.add(10);
}

And count down at the end of the drawing method like this

@Override
public void paintComponent(Graphics g) { // this is called by JFrame.paint()
    super.paintComponent(g);
    // ...
    jFrameDrawing.countDown();
}

Now note, that this method might be called multiple times before p is really fully drawn. The reason is the following Is the paint function in java graphics called multiple times when I add a JComponent?

So if your main looks like this:

public static void main(String[] args) {
    List<Integer> l = new ArrayList<Integer>(5);
    CountDownLatch jFrameDrawing = new CountDownLatch(3); // NOTE 3
    JFrame gui = new JFrame();
    gui.add(new MyPanel(), jFrameDrawing); // draw once
    gui.setSize(100,50); // draw again
    gui.setVisible(true); // draw a third time
    try {
        jFrameDrawing.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    l.add(10);
}

You need to set the initial counter to 3.

TL;DR: Using AWT classes (e.g. JFrame) in

object.function2();

will create multithreading. This might create race conditions, like lists being modified concurrently. See Java wait for JFrame to finish on how to think the drawing with the main code.

Aracurunir
  • 625
  • 6
  • 10
  • Thank you so so much for your time and effort. Your post helped me see the problem and come up with a solution (I ended up just deep-cloning the Network Object and drawing the clone so there wouldn't be any conflicts with multi-threading). – MrQweep Nov 14 '16 at 21:11