有没有办法在不调用 System.exit() 的情况下终止使用 java3d 的 java 应用程序?

2024-01-12

Java3D 启动多个系统线程,并且不会在它们上设置 isDaemon 标志。当我处置应用程序的(唯一)JFrame 时,它​​不会终止,因为这些线程仍在运行。

调用 System.exit() 似乎是终止应用程序的唯一方法。 (当然,或者从外部杀死它)。

由于我不喜欢调用 System.exit() 我尝试了以下操作(但没有成功):

  • 在 VirtualUniverse 上调用removeAllLocales():这会终止大多数线程,但仍然有一个线程(名为 J3D-Renderer-1)剩余。
  • 使用反射获取对 javax.media.j3d.MasterControl 中 ThreadGroup rootThreadGroupp 字段的引用,并在该 ThreadGroup 上设置 isDeamon true。这似乎没有任何效果。
  • 获取对名为“Java3D”的 ThreadGroup 的引用并对其调用 Interrupt():这会导致 java3d 线程将 InterruptedException 写入 stderr,但不会写入其他内容。
  • 找到 Java3d-core 库的源代码并提出补丁:我在这里找到了一个存储库:https://github.com/hharrison/java3d-core https://github.com/hharrison/java3d-core和这里:https://java.net/projects/j3d-core/sources https://java.net/projects/j3d-core/sources。后一个看起来是“官方的”,但显示了它的最后一次更改发生在 5 年前,而前一个对我来说看起来像是一个私人分叉。

我几乎要放弃并调用 System.exit(),但我仍然不喜欢它。你知道更好的方法吗?


一种可能的解决方案是调用Java3dThread.finish()Java3D 线程上的方法。缺点是必须绕过 java 访问规则才能调用此方法,因为它是包私有的。这段代码对我来说很有效:

public void dispose() {
    virtualUniverse.removeAllLocales();
    try {
        // give the Java3D threads the chance to terminate peacefully.
        Thread.sleep(250);
    } catch (final InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    // and now handle the threads that didn't take the hint
    finishJava3dThreads();
}

private static void finishJava3dThreads() {
    final Class<?> rendererClass;
    final Method finishMethod;
    try {
        rendererClass = Class.forName("javax.media.j3d.J3dThread");
        finishMethod = rendererClass.getDeclaredMethod("finish");
        finishMethod.setAccessible(true);
    } catch (ClassNotFoundException | NoSuchMethodException | SecurityException e) {
        throw new RuntimeException(e);
    }
    final ThreadGroup[] groups = new ThreadGroup[10];
    final int count = Thread.currentThread().getThreadGroup().getParent().enumerate(groups);
    for (int i = 0; i < count; i++) {
        final ThreadGroup threadGroup = groups[i];
        if ("Java3D".equals(threadGroup.getName())) {
            threadGroup.setDaemon(true);
            final Thread[] threads = new Thread[threadGroup.activeCount()];
            final int threadCount = threadGroup.enumerate(threads);
            for (int j = 0; j < threadCount; j++) {
                final Thread thread = threads[j];
                if (rendererClass.isInstance(thread)) {
                    try {
                        finishMethod.invoke(thread);
                    } catch (IllegalAccessException | InvocationTargetException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
            Thread.yield();
            threadGroup.interrupt();
        }
    }
}

其中 virtualUniverse 是应用程序中先前创建的 VirtualUniverse 的实例。

现在我称之为dispose()终止应用程序时终止 Java3D 的方法:

   addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosed(final WindowEvent e) {
            plater.dispose();
        }
    });

Where plater是包含以下内容的实例dispose()方法从上面。

其他一切都只是处理主 JFrame:

    actions.put(EXIT_ACTION, new AbstractAction(EXIT_ACTION) {
        @Override
        public void actionPerformed(final ActionEvent e) {
            dispose();
        }
    });

并且默认关闭操作也设置为DISPOSE_ON_CLOSE:

    setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);

但不确定这是否是最好的选择。 (相比之下,我还是更喜欢它System.exit()调用,但以这种方式使用反射有些脆弱。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

有没有办法在不调用 System.exit() 的情况下终止使用 java3d 的 java 应用程序? 的相关文章

随机推荐