【问题标题】:GUI/Threading Instability in Java on OS X; seems to be related to the Swing/AWT -> Cocoa bridgeOS X 上 Java 的 GUI/线程不稳定;似乎与 Swing/AWT -> Cocoa 桥有关
【发布时间】:2011-06-22 21:41:31
【问题描述】:

我遇到了一个非常令人沮丧的问题,涉及 OS X 和 Java Swing GUI;特别是我遇到了 Cocoa 兼容模式的问题。

我在机器人实验室工作,我们的很多软件都是通过内部模拟套件运行的。该模拟套件的代码已有近 10 年的历史,由我们的一位首席研究人员在他上大学时创建。模拟在 Swing GUI 中运行。模拟在 Linux 和 Windows 计算机上都可以正常运行,但不能在 OS X 上运行。

需要明确的是,我正在编写的代码不是 GUI 代码。我不是“GUI Guy”。然而,他很久以前编写的代码提供了一个 API,用于快速创建基于关节和链接的标准机械系统的机器人模型模拟,这些模拟以 GUI 的形式出现,以便于启动、停止、记录、回放、跟踪变量等操作,创建绘图等。所以我没有直接调用任何 Swing 代码;这是我们每个模拟使用的所有“沼泽标准”(对我们的情况而言)。而且每一个都在 OS X 上崩溃,而在 Windows 和 Linux 下运行得很好。

我浏览了互联网,虽然我无法找到解决问题的方法,但问题的根源似乎是 Cocoa 兼容模式要求程序员遵守严格的图形线程指南接口。似乎弹出最多的一个例子是,如果您不使用SwingUtilities.invokeLater() 线程化您的GUI,那么您的代码将不稳定。编写代码的人承认,当他最初创建 API 时,他并没有遵循最佳线程实践。

Cocoa 兼容模式似乎对某种 Swing 操作强制某种超时,不太确定它是什么,但我使用的是 2011 年 MacBook Pro,2.3 GHz 四核i7、8 GB RAM、一个 SSD 和一个 1 GB Radeon 6750M。我想我没有遇到某种超时。

我们在 Eclipse 中开发,并从 Eclipse 启动我们的模拟程序(我们不需要将它们转换为任何形式的可执行文件)。启动模拟时,GUI 会出现并完全填充。但是,它不能与之交互。即使是“红绿灯”也永远不会激活,因此终止 GUI 的唯一方法是使用 Eclipse 中的终止按钮。

Here is a screenshot of what the console looks like。我不是 Cocoa 开发人员,所以错误本身对我来说意义不大,但我知道 NS 前缀意味着错误来自 Cocoa,我知道似乎正在发生的事情是某种线程经理(可能是 Grand Central Dispatch?)正在尝试对空锁对象进行操作,并且在某个时候或另一个线程池存在问题。

据我所知,目前无法禁用 Cocoa 兼容模式(似乎曾经使用 Apple 特定的 java 系统属性,但该属性不再出现在提供的有效系统属性列表中Apple 开发者网站)。我也尝试使用 -XstartOnFirstThread 参数无济于事。虽然我们的实验室主要是 Linux 和 Windows 驱动,但我们的组织规模很大,并且不同的团队想要开始使用我们为他们的项目创建的一些模拟,这个部门主要是使用 Mac 的部门(我也是我自己是 OS X 用户,所以我想继续使用我的 MBP)。

那里的任何人都可以告诉我是否有办法禁用 Cocoa 兼容模式,或者至少我的怀疑是否正确:是什么导致了错误?我们不是官僚机构,我们的老板知道代码有错误,所以如果我的预感是正确的,那么执行直觉和重写并不是不可能的,就像在大公司那样。正如我已经说过的那样,模拟在其他操作系统上没有稳定性问题,并且许多源于 OS X 限制的稳定性问题似乎与提供愉快的用户体验有关,我们并不真正关心,因为这不是面向用户的产品。它根本不是产品。

我不是在寻找与我谈论 UX/UIX、非阻塞 UI 或线程/UI 设计最佳实践的 cmets 或答案。这些都是我所熟悉的,而这些也是我的上司更熟悉的。我只是希望有人可以帮助我消除 OS X 对我们的 Java 代码任意设置的限制,有人可以为我指明正确的方向,以便我们可以让我们当前的代码符合操作系统的限制。

我正在使用适用于 OS X 的最新 JVM/JDK、最新的 OS X 开发工具和最新版本的 Snow Leopard。

编辑:这是一个自包含并编译的Gist。它完全没有响应,就像上面一样,虽然它没有所有的空锁错误,但它确实有自动释放错误并且在 OS X 上不起作用。

【问题讨论】:

  • 您的应用程序是否使用com.apple.eawt.CocoaComponent 以及 Swing?
  • 重现问题的sscce 可能有助于澄清问题。
  • @trashgod 不,我们不使用 CocoaComponents,此代码不是为 OS X 编写的,并且是在 10 多年前创建的。我想如果它确实使用了这些东西,它可能不会像现在这样在 Windows 或 Linux 上运行。
  • 此外,发布代码 sn-p 绝对没有意义,因为这基本上会涉及发布整个庞大的 API,因为所有 Swing 代码都在 API 中。我不会把我们实验室的整个代码库都放在 SO 上。
  • 我完全同意,sn-p 是没用的; sscce 可能会有所帮助,但可靠的错误线程通常是显而易见的。我在 Mac OS 上编写了很多跨平台的 Swing,而且我不得不不止一次地在遗留代码中追踪这些东西。 Mac OS 可能会暴露问题,但这是巧合。我很同情,但我不知道如何以目前的形式回答这个问题。

标签: java swing macos user-interface crash


【解决方案1】:

我遇到了同样的问题(在相同的 macbook 配置上)并发现了错误描述 here

首先,我在 OSX 上安装了 openjdk 7:

我在 Eclipse 中更改了我的项目构建路径以指向新安装的 jdk.1.7.0u (在我的 Mac 上:/Library/Java/JavaVirtualMachines/1.7.0u.jdk/Contents/Home/)并且 UI 不再冻结。

【讨论】:

  • 我会玩弄这个,但是我们的很多内部库都依赖于被 OpenJDK 小组认为是遗留的代码,并且没有在 OpenJDK 中实现(例如:com.sun.image .codec.jpeg),所以我们不应该在我们的开发机器上使用 OpenJDK 实现。因为我们所有的代码都必须针对机器人的 Real Time Java 构建,所以这不是问题,因为 RT Java 规范针对 1.5 系统库构建,我们仍然可以获得用于 Linux 的 1.5 和 1.6 Sun/Oracle JDK。不过,我会看看我能做些什么。感谢您的提示。
  • 这绝对让 Swing/AWT 在 Lion 下工作。仍然需要解决我们实验室的东西对 Sun 代码的依赖,但感谢您的建议。
【解决方案2】:

除了缺少尾括号外,您的示例和以下变体在使用 Java 1.6.0_24 的 Mac OS 10.5.8 上按预期运行。特别是鼠标、键盘和焦点都显示正常。请注意,JFrameadd()setLayout()(以及其他)转发到内容窗格。我只是不习惯替换内容窗格。

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class FrameExample2 extends JFrame {

    private JPanel panel = new JPanel();
    private JTextField xAccelTextField = new JTextField(10);
    private JSlider xAccelSlider = new JSlider();

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                try {
                    FrameExample2 frame = new FrameExample2();
                    frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace(System.out);
                }
            }
        });
    }

    public FrameExample2() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        panel.setLayout(new GridLayout(0, 1));
        panel.setBorder(BorderFactory.createLineBorder(Color.gray, 8));
        panel.add(new JLabel("Linear Acceleration along X", JLabel.CENTER));
        panel.add(xAccelSlider);
        xAccelTextField.setEditable(false);
        xAccelTextField.setText("0");
        panel.add(xAccelTextField);
        xAccelTextField.setColumns(10);
        this.add(panel);
        this.pack();
        this.setLocationRelativeTo(null);
        xAccelSlider.addChangeListener(new ChangeListener() {

            @Override
            public void stateChanged(ChangeEvent e) {
                xAccelTextField.setText(
                    String.valueOf(xAccelSlider.getValue()));
            }
        });
    }
}

【讨论】:

  • 它在 Leopard 上工作的事实让我认为问题出在 64 位 JVM 上。我会尝试使用 -d32 看看它是否运行。
  • 很抱歉报告负面调查结果。如here 所述,您可能会寻找不定的 JAR。
  • 32 位 JVM 没有帮助。叹。不过感谢您的帮助。
  • 是的,我很茫然。显然 Swing 可以在 OS X 上运行,否则 Eclipse 本身将无法启动。这是很多人似乎在搜索 SO 时遇到的问题。但没有人对此有答案。我认为这真的很愚蠢,就像缺少原生库一样。
  • 在 NetBeans 和 Eclipse 中运行良好。注意 Eclipse 使用 SWT,而不是 Swing。
猜你喜欢
  • 1970-01-01
  • 2010-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-17
  • 2010-10-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多