有没有办法终止使用java3d的java应用程序,而无需调用System.exit()?

Java3D启动了几个系统线程,并没有在它们上设置isDaemon标志。 当我处置我的应用程序的(仅)JFrame时,它将不会终止,因为这些线程仍在运行。

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

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

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

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

一种可能的解决方案是在Java3D线程上调用Java3dThread.finish()方法。 缺点是必须绕过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(); } }); 

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()调用上,但是以这种方式使用reflection有点脆弱。)

System.exit(0)是结束程序的正确方法。

这是在程序中处理关闭的便捷方式,程序的某些部分无法相互识别。 然后,如果某个部分想要退出,他可以简单地调用System.exit(),并且关闭挂钩负责执行所有必要的关闭任务,例如:关闭文件,配置打开的窗口和释放资源。

阅读有关关闭钩子的文档。