【问题标题】:Unexplained Java shenanigans - possibly to do with threading?无法解释的 Java 恶作剧——可能与线程有关?
【发布时间】:2011-06-13 07:50:44
【问题描述】:

问题

我目前正在使用 Swing GUI 在 Java(在 Eclipse 中)构建 Game of Life 模拟器,作为大学项目的一部分。除了一个小缺陷之外,这一切进展顺利 -

它适用于我的上网本,但不适用于我尝试过的任何其他 PC。这是在 Ubuntu 下。

一些结构大纲 - 我有一个模型、一个视图和一个控制器。我还没有正确定义模型,但是我已经完成了视图(GUI 部分)并启动了控制器。 Controller通过Main方法运行,然后Controller在单独的线程中创建View类并进入while循环。

视图实现了从用户输入、鼠标点击等接收到的“订单”队列。控制器在 while 循环的迭代中从队列中挑选这些订单,并在必要时执行它们。

然而,虽然代码在我的上网本(最新版本,Java 1.6.0_20)上运行良好,但它在我的电脑(最新版本,Java 1.6.0_20)或大学电脑(karmic,以前的一些Java 版本)。一旦遇到“getNextCommand”方法,它就会停止。 没有错误,只是拒绝打印/遵守

源文件位于此处 - http://www.mediafire.com/?dfwtdkj1tdxd5xl 感兴趣的文件是 Controller 和 View。

示例

在视图中,我有这个功能:

public Command getNextCommand() {
  System.out.println(commands.getFirst().id);
  return commands.pop(); 
 }

非常不言自明,当 Controller 调用 getNextCommand() 时,它会打印出是什么命令。

这是Controller中的while循环:

while(!stop) {
   if (gui.hasCommand()){
    order = gui.getNextCommand();
    //System.out.println("Something");
    //if(order.id.equals("stop")) { stop = true; }
   }
  }

这很好用。如您所料,它会在 getNextCommand 中打印。

尽管取消注释这两个语句中的任何一个,它都会突然停止工作。不再为您打印!

为什么会发生这种情况?为什么这可以在我的上网本上工作,但不能在我的电脑上工作? :C

补充说明

此外,如果我运行 Eclipse 生成的 .class 文件,它会打印(假设这两行已被注释掉)。如果我只是使用 javac 自己编译它们,则不会打印任何内容。

任何见解将不胜感激!

谢谢,

卢克。

编辑

如果我在调用 getNextCommand 时没有返回一个命令(一个简单的容器类,带有一个 id (String)、x,y (int) 和 value (int)),而是返回一个整数,则会出现同样的问题。或者别的什么。

【问题讨论】:

  • 我没有答案,但你有我的同情!对于一种本应“编写一次,随处运行”的语言来说,绝非如此。
  • @ראובן:当您使用以非同步方式相互交互的多个线程时,请指出一种不会导致未定义行为的语言。

标签: java multithreading eclipse swing


【解决方案1】:

更有可能存在您没有捕获或未正确处理的错误。仔细检查您是否没有抛出异常。

您还尝试删除您认为不相关的程序片段,并确保它不断失败。这将帮助您找出真正的根本原因。

【讨论】:

  • 我同意,但真正让我感到奇怪的是,它在我的上网本(运行桌面操作系统,而不是 NBR)上运行得非常好并且符合预期,但不能我的电脑。它们实际上是彼此的复本。一旦我注释掉这两行代码,它就会停止失败。
  • Java 是可移植的,但操作系统之间仍然存在一些问题。例如,Windows 接受错误大小写的文件名,但 Linux 不接受。我并不是说其中一个是正确的,但是如果您有一个名为 Help.PNG 的图像并在 java 中将其称为 Help.png,它可能在一个操作系统上工作,但在另一个操作系统上找不到。
  • @Luke:如果有竞争条件,你可能只是在一个环境中走运了,它并没有暴露给你。这并不意味着它不会持续两个月,也不会使程序正确。
【解决方案2】:

我们需要更多信息。 commands 是什么类型?

无论哪种方式,比忙碌等待(在 while 循环中旋转)更好的解决方案是拥有某种等待/通知机制。您的问题的明显候选者似乎是BlockingQueue(如ArrayBlockingQueueLinkedBlockingQueue)。这种类型的检索方法会阻塞直到有可用的数据(命令),而不是要求你不断地轮询直到有可用的命令。

例如

BlockingQueue<Command> commands = new LinkedBlockingQueue<Command>();

//...

//wait for the next element and then get it
while(!stop) {
   Command nextCommand = commands.take();
   //do something with nextCommand
}

参考

【讨论】:

  • Ah - Commands 是一个包含 id、x、y 和值的简单类。例如,如果我用 Integer 替换它,也会出现同样的问题。
  • @Luke Tomlin:但它有一个getFirst() 方法。你确定你不是在想Command?我想要的是,变量commands 是如何声明/定义的?
【解决方案3】:

嗯,这是多线程问题的典型案例,因为您从不同的线程调用视图和控制器。假设您的命令容器未同步。

可能发生的情况是命令的更新是由一个线程完成的,但是其他线程没有注意到它,因为更新不在同步块内。可以把它想象成两个线程在不同的 CPU 缓存上工作 - 当一个线程写入时,另一个线程看不到它,除非它导致缓存被刷新到主内存中 - 这只发生在调用同步时。

更多:http://gee.cs.oswego.edu/dl/cpj/jmm.html

快速解决方案:使用 java.util.vector 代替 LinkedList

【讨论】:

  • 你是个天才!非常感谢:)
  • 这可能会让事情变得线程安全,但你仍然会面临可怕的忙碌等待。这就是为什么我在回答中建议使用阻塞数据类型。
  • @Mark Peters - 我也会实现它,别担心!我主要专注于解决这个问题,因为它抑制了其他一切。谢谢你的建议:D
猜你喜欢
  • 1970-01-01
  • 2015-01-13
  • 1970-01-01
  • 2011-07-31
  • 2010-09-23
  • 1970-01-01
  • 2023-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多