Java 退出Swing应用程序时偶尔出现中断异常

Java 退出Swing应用程序时偶尔出现中断异常,java,concurrency,multithreading,java-2d,interrupted-exception,Java,Concurrency,Multithreading,Java 2d,Interrupted Exception,我最近更新了我的计算机,使其功能更加强大,配备了四核超线程处理器(i7),从而提供了大量的实际并发性。现在,我在退出(System.exit(0))我正在开发的应用程序(带有Swing GUI)时,偶尔会遇到以下错误: Exception while removing reference: java.lang.InterruptedException java.lang.InterruptedException at java.lang.Object.wait(Native Me

我最近更新了我的计算机,使其功能更加强大,配备了四核超线程处理器(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在哪里

以前有人经历过类似的事情吗?有没有办法开始解决这个问题

Edit:由于退出带有
System.exit(0)
的Swing应用程序可能“不干净”,但我不想将主框架设置为
exit\u ON\u CLOSE
,因为我想确保应用程序退出时不会发生任何关键事件,所以我添加了一个机制,以便它执行主框架的
dispose()
方法,然后调用
系统。退出(0)
。所以现在应该很干净了,但偶尔还是会有例外。调用
系统退出(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()
array(它包含无所有者的
对话框等)来显式地处理所有
窗口
s,但没有任何区别。这个问题似乎与“清洁”没有什么关系(即在退出之前显式释放本机屏幕资源)。是别的,但是什么

编辑2:将默认关闭操作设置为关闭时退出没有任何区别。找到一些bug报告,所以这可能确实是Sun的Java2D实现中的bug。我可以想象,像这样的错误可以在很长一段时间内不被修复,因为它们在实践中是相当无害的;来自关闭挂钩的异常几乎不会伤害任何其他人。鉴于这种情况发生在GUI应用程序中,除非将
stderr
定向到控制台或日志,否则不会注意到异常情况。

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

无法将主框架设置为在关闭时退出:

mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE )
然后将其设置为不可见


相关Q在这里

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

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


如果是这种情况,一种解决方法是在主线程上触发Java2D操作(即,当应用程序启动时立即触发),从而使DisposerThread处于“干净”的环境中。它是由静态初始值设定项启动的,因此只需虚拟加载一个java2d资源并释放它就足以获得一个不会挂起不需要的东西的DisposerThread。

如果使用,则可以覆盖
应用程序.exit()
以执行清理,或者添加
ExitListener
。否则,您还可以向应用程序添加一个关机挂钩,
Runtime.getRuntime().addShutdownHook()

听起来你有一个线程在运行,当你退出时它还没有终止。值得注意的是,线程正在等待,如果您试图在线程运行时停止线程,该方法将抛出一个中断的异常。我总是将后台线程设置为作为守护进程运行,这可能也会有所帮助

我将在您的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();
  }
});
通过手动中断循环,您允许wait方法终止(希望您没有等待太长时间,是吗?如果是,您可能想重新检查您是如何利用线程的),然后在代码中找到一个安全的中断点-因为您将其编码为安全-然后线程将终止,让应用程序正常终止

更新
也许您在某个地方不恰当地使用了事件调度线程,而当您尝试退出时,它正在等待/仍在为您工作?dispatcher线程应该尽可能少地执行工作,并且应该尽可能快地将任何复杂的任务传递给另一个线程。我承认我是在暗中摸索,但我倾向于认为这不是一个bug,特别是考虑到你开始在一台功能更强大的机器上注意到它——对我来说,这是“竞争条件!”而不是Java bug。

Java线程只有在所有run()方法完成执行后才会终止。否则,VM中的线程扩展对象将一直处于混乱状态。您必须在退出应用程序之前完成所有线程


也可以考虑,当你创建JFrice时,你正在启动一个线程(CurrnTythType,我相信)

< P>你的处理程序在调用Read()中被阻塞(删除下一个平台的本地资源)。这意味着当VM退出时,处理器线程(守护进程线程)不会自然关闭(这是您应该预料到的,因为您是通过System.exit()终止它)

您的应用程序中有一个非守护进程线程,它阻止VM在所有swing窗口都被释放后退出

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

通常,如果一个swing应用程序的所有swing窗口都已处理完毕,则该应用程序将正常退出,例如,该程序将弹出一个窗口,然后在关闭后退出(所有操作均不调用System.exit()):


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

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

当您有一个基本的java应用程序和一个
public static void main(String args[]) throws Exception {
    JFrame jf = new JFrame();
    jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    jf.setVisible(true);
}
JFrame frame=this.getFrame();
if(frame!=null)
{
   Window[] windows=frame.getWindows();
   for(Window window : windows)
   window.addWindowListener(this);
}
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) {}
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
}
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);
}
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();
        }
    });
}
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(); }
}
Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    });