退出Swing应用程序时偶尔会出现InterruptedException

我最近将我的计算机更新为更强大的计算机,配备了四核超线程处理器(i7),因此可以提供大量真正的并发性。 现在我在退出( System.exit(0) )我正在开发的应用程序(使用Swing GUI)时偶尔会出现以下错误:

 Exception while removing reference: java.lang.InterruptedException java.lang.InterruptedException at java.lang.Object.wait(Native Method) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:134) at sun.java2d.Disposer.run(Disposer.java:125) at java.lang.Thread.run(Thread.java:619) 

好吧,鉴于它开始发生在具有更多并发能力的硬件上,并且它与线程有关,并且它偶尔发生,它显然是某种时间性的东西。 但问题是堆栈跟踪太短了。 我只有上面的列表。 它根本不包含我自己的代码,因此有点难以猜测bug的位置。

以前有没有经历过这样的事情? 任何想法如何开始解决它?

编辑:因为退出使用System.exit(0)的Swing应用程序可能是“不干净”,但我不想将主框架设置为EXIT_ON_CLOSE因为我想确保在应用程序退出时没有任何关键问题,我添加了一个机制,以便在调用System.exit(0)之前执行主框架的dispose()方法。 所以它现在应该很干净,但偶尔也会发生exception。 它发生在调用System.exit(0)之后; dispose()没有问题。 也就是说,它必须来自一个关闭钩子:

 mainFrame.dispose(); // No problem! After this returns, all visible GUI is gone. // In fact, if there were no other threads around, the VM could terminate here. System.exit(0); // Throws an InterruptedException from sun.java2d.Disposer.run 

我甚至尝试通过循环遍历Window.getWindows()数组(它包含无主Dialog等)显式处理所有Window ,但它没有区别。 这个问题似乎与“清洁度”(即在退出前明确释放本机屏幕资源)无关。 这是别的什么,但是什么?

编辑2:将默认关闭操作设置为EXIT_ON_CLOSE没有任何区别。 http://www.google.com/search?q=sun.java2d.Disposer.run(Disposer.java:125)发现了一些错误报告,所以这可能确实是Sun的Java2D实施中的一个错误。 我可以想象像这样的虫子可以长时间不固定,因为它们在实践中是非常无害的; 关闭钩子的例外几乎不会伤害任何其他人。 鉴于这种情况发生在GUI应用程序中,除非将stderr定向到控制台或日志,否则甚至都不会注意到该exception。

您的Disposer在调用remove()时被阻止(删除下一个平台本机资源)。 这意味着当VM退出时,处理程序线程(守护程序线程)不会自然关闭(您应该期望通过System.exit()终止它)。

您的应用程序中有一个非守护程序线程,当您所有的摆动窗口都被丢弃时,它会阻止VM退出。

解决方案 :找到它并使其退出。

通常情况下,如果摆动应用程序的所有摆动窗口都已被处理掉,它将正常退出,例如,该程序将弹出一个窗口,然后一旦关闭就退出(所有这些都没有调用System.exit()):

 public static void main(String args[]) throws Exception { JFrame jf = new JFrame(); jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); jf.setVisible(true); } 

您也可以在退出之前尝试运行垃圾收集器,只是为了踢。

如果您正在使用swing应用程序,则首先调用System.gc()然后调用dispose()方法。 我认为它会工作正常..我也使用它。

想投票,但我需要更多的代表。 这个解决方案对我有用,虽然我找不到解释原因,而我的同事也说这没有意义。

我有1.7和我创建的swing应用程序,它读取文件,重新排列内容然后输出到文件。 有一个运行和退出按钮。 使用首选项API,编写器,阅读器和其他一些东西。 一旦打开和关闭应用程序(没有System.gc() ),连续两次将连续返回如上所述的相同exception。 但是在dispose()之前使用System.gc()我无法再次抛出exception。

System.exit()可能不是关闭基于Swing的应用程序的最干净的方法

你不能将主框架设置为EXIT_ON_CLOSE:

 mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ) 

然后把它设置为隐形?

相关问题在这里; java中的System.exit(0)

我想知道它是否与这个bug无关:

Java Bug 6489540

基本上它意味着如果在存在InheritableThreadLocal对象或存在自定义contextClassLoader时使用Java2D,它们将被捕获并永久存在,从而导致内存泄漏,并可能出现这种奇怪的锁。

如果是这种情况,则解决方法是在主线程上触发Java2D操作(即,在应用程序启动时立即执行),以便DisposerThread生活在“干净”的环境中。 它是由一个静态初始化程序启动的,所以只需一个java2d资源的虚拟加载并释放它就足以得到一个不会挂起不良内容的DisposerThread。

我想我已经找到了bug的来源!

当你有一个带有退出子菜单的基本java应用程序进入文件菜单…有一个快捷方式来激活退出操作…这个快捷方式必须创建一个循环链接或类似的东西…

有解决方案:

首先,这是可选的全部清除:从主窗口实现此接口“WindowListener”。

在构建这个主窗口时,请执行以下操作:

 JFrame frame=this.getFrame(); if(frame!=null) { Window[] windows=frame.getWindows(); for(Window window : windows) window.addWindowListener(this); } 

从界面实现function:

 public void windowOpened(WindowEvent e) {} public void windowClosing(WindowEvent e) { JFrame frame=this.getFrame(); if(frame!=null) { Window[] windows=frame.getOwnedWindows(); for(Window window : windows) { window.removeWindowListener(this); window.dispose(); } } //clear(); System.gc(); } public void windowClosed(WindowEvent e) {} public void windowIconified(WindowEvent e) {} public void windowDeiconified(WindowEvent e) {} public void windowActivated(WindowEvent e) {} public void windowDeactivated(WindowEvent e) {} 

在那之后你必须小心你的快捷方式! 您必须从Exit菜单中删除Action才能使用actionPerformed管理它:

 private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) { //this.clear(); svExitMenuItem.removeActionListener(null);//this call removes the end error from this way to exit. javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(etscampide.ETScampIDEApp.class).getContext().getActionMap(ETScampIDEView.class, this); actionMap.get("quit").actionPerformed(null);//null to avoid end error too } 

我不解释为什么但它对我有用…我认为有一种循环参考…希望能帮助你。 再见。

我有同样的问题(Java 6)。 我注意到调试器中有一个unknwon sun.awt.image.ImageFetcher线程。 我认为它来自于我使用JButtons with Icons。 ImageFetcher线程在2秒后消失。 如果ImageFetcher线程未运行,我的程序退出就好了。

听起来你有一个运行的线程,当你退出时它没有终止。 值得注意的是,该线程是wait()ing,如果您尝试在线程运行时停止该线程,则该方法会抛出中断的exception。 我总是设置后台线程作为守护进程运行,这也可能有所帮助。

我会在你的JFrame中执行以下操作:

 myJFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { // Some pieces of code to instruct any running threads, possibly including // this one, to break out of their loops // Use this instead of System.exit(0) - as long as other threads are daemons, // and you dispose of all windows, the JVM should terminate. dispose(); } }); 

通过手动断开循环,你允许等待方法终止(希望你不会等待很长时间,是吗?如果你是,你可能想重新检查你如何利用你的线程)然后得到到你的代码中可以安全破解的一点 – 安全因为你编写了这样做 – 然后线程将终止,让应用程序终止正常。

更新也许您正在某处不恰当地使用事件派发线程,当您尝试退出时,它正在等待/仍在为您工作? 调度程序线程应该尽可能少地工作,并且应该尽可能快地将任何复杂的东西传递给另一个线程。 我会承认我在黑暗中徘徊了一点,但我倾向于认为这不是一个错误,特别是考虑到你开始在一台更强大的机器上注意到它 – 这让我尖叫“竞争条件!” 不是Java bug。

有时会再次出现错误,但这似乎工作正常:

 private void exitMenuItemActionPerformed(java.awt.event.ActionEvent evt) { svExitMenuItem.removeActionListener(null); windowClosing(null);//i add it to clear and call the garbadge collector... javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(etscampide.ETScampIDEApp.class).getContext().getActionMap(ETScampIDEView.class, this); actionMap.get("quit").actionPerformed(null); } 

我遇到了同样的问题,发现我只是在背景中隐藏了一个Frame(我把它的可见性设置为false)。 如果我确保在我的隐藏框架上调用.dispose()然后在我的mainFrame上调用.dispose(),我就不需要调用System.exit(0),应用程序只是自行清理并关闭。 我的代码是Scala,但想法是一样的。

 def top = new MainFrame { import javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE peer.setDefaultCloseOperation(DO_NOTHING_ON_CLOSE) override def closeOperation() { endExecution; PreviewFrame.dispose(); this.dispose(); } } 

如果您使用的是Swing App Framework ,则可以覆盖Application.exit()以执行清理,或者也可以添加ExitListener 。 否则,您还可以向应用添加一个关闭钩子Runtime.getRuntime().addShutdownHook()

java中的线程仅在所有run()方法完成执行时终止。 否则,你将永远在VM中使用那些Thread扩展对象。 您必须在退出应用程序之前完成所有线程。

还要考虑在创建jFrame时,你正在启动一个线程(我相信CURRENT_THREAD)

我得到了一个类似的错误,不知怎的,这对我有用:

 private static void createAndShowGUI() { JFrame jf = new MyProgram(); jf.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGUI(); } }); } 

尝试使用EventQueue.invokeLater()关闭Swing。

这似乎是Java 1.7中解决的错误。

配置我的Eclipse在jdk 1.7中运行,错误就消失了。

约阿夫

我刚刚使用数据库遇到了这个错误。 问题是没有关闭与数据库的连接。 我通过使用以下代码解决了这个问题:

 Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }); 

把它扔给其他人……

尝试这个。 这对我有用。 我正在创建在System.exit(0)调用后未正确处理的JFileChooser实例。

 setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent ev) { dispose(); System.exit(0); } }); 

如果您正在使用swing应用程序,则首先调用System.gc()然后调用dispose()方法。 我认为它会工作正常..我也使用它。