Java 在我的代码中跳转

Java jumping ahead in my code

我 运行 遇到一个问题,其中 java 完全错误地解释了我的代码,我不知道如何更改它。由于我的程序太复杂,无法真正解释,所以我将对我的问题进行概括性描述,希望您能给我一个概括性的答案。 在我的代码中有一些类似的东西:

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

function1 改变对象。

当我 运行 this 时,我在 function2 内部遇到异常(这意味着代码永远不会到达第三行)。但是,当我删除第三行时,代码 运行s 没有任何问题。这意味着 java 编译器正在编译我的代码,使得 function1 的第二次调用对调用 object.function2 的前一行有一些影响。 同样有趣的是,如果在第 2 行和第 3 行之间插入一个断点,它在调试时始终有效。

这正常吗? java 中是否有任何原则导致了这种情况,以及有什么方法可以阻止这种情况? 该代码可在 Bitbucket Repository 获得,但请注意,它是未记录的意大利面条代码,可能违反 java 代码中的所有约定。描述的问题在 Pool.java 内,从第 41 行开始。

我希望我在这里提供的少量信息足以进行某种解释。

好吧,我认为已经足够了解这个问题,能够创建一个可能对您(当然)和希望对其他人有帮助的答案。

确实涉及到多线程,因为

object.function2();

正在创建一个 JFrame f。该帧 f 内的所有绘图操作都由 AWT-EventQueue-0(或任何其他数字)任务 T。此任务 T 运行 与您的主线程 M 并行。意思是在 f 内的自定义 JPanel p 中绘制的每个数据结构 l(如列表)和由 M 改变可能会导致问题。

例子

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));
        }
    }
}

现在调用创建 JFrame 后更改 l 的大小,我们会导致 ArrayOutOfBoundsException 当试图访问 modifiedL.get(5) 时,因为 modifiedList 可能在 l.add(10)[=64 之前创建=].

(一个可能的)解 请注意,我写了 possible,因为这是 hacky 并且尽可能避免。 我们需要主线程 M 等待所有内容绘制完成。这是一种方法: Java wait for JFrame to finish 在我们的示例中,我们可以将 main 更改为:

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);
}

然后像这样在绘图方法结束时倒计时

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

请注意,在 p 真正完全绘制之前,可能会多次调用此方法。原因如下

因此,如果您的主要内容如下所示:

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);
}

您需要将初始计数器设置为 3。

长话短说: 在

中使用 AWT 类(例如 JFrame
object.function2();

将创建多线程。这可能会产生竞争条件,例如同时修改列表。 看Java wait for JFrame to finish如何用主代码思考绘图。