我遇到了一个问题,即java解释我的代码完全错误,我不知道如何改变它。由于我的程序太复杂而无法解释,我将对我的问题进行概括性描述,并希望你能给我一个通用的答案。 在我的代码中有一些类似的东西:
function1();
object.function2();
function1();
function1
改变了对象。
当我运行它时,我在function2
内部得到一个异常(意味着代码永远不会到达第三行)。但是,当我删除第三行时,代码运行没有任何问题。这意味着java编译器正在以这样的方式编译我的代码:function1
的第二次调用对调用object.function2
的前一行有一些影响。
同样有趣的是,如果在第2行和第3行之间插入断点,它在调试时总是有效。
这是正常的吗? java中是否存在导致此问题的原因,以及任何阻止此问题的方法? 代码在Bitbucket Repository处可用,但要注意,它是未记录的意大利面条代码,可能违反了java代码中的所有约定。描述的问题在Pool.java里面,从第41行开始。
我希望我在这里提供的一些小信息足以作出某种解释。
答案 0 :(得分:0)
好吧,我认为已经弄清楚了这一点,能够创造一个可能对你有帮助的答案(当然),并希望其他人能够帮助你。
确实涉及多线程,因为
object.function2();
正在创建 JFrame f 。该框架 f 内的所有绘图操作都由 AWT-EventQueue-0 (或任何其他编号)任务 T 执行。此任务 T 与主线程 M 并行运行。表示在 f 内的自定义 JPanel p 中绘制并由 M l (如列表) >可能会导致问题。
示例强>
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)之前创建。
(可能)解决方案 请注意,我写的可能,因为这是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 之前,可能会多次调用此方法。原因如下 Is the paint function in java graphics called multiple times when I add a JComponent?
所以如果你的主要看起来像这样:
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。
TL; DR: 在
中使用 AWT 类(例如 JFrame )object.function2();
将创建多线程。这可能会创建竞争条件,例如同时修改列表。 请参阅Java wait for JFrame to finish,了解如何使用主代码思考绘图。