Подтвердить что ты не робот

Случайное прерывание Исключения при выходе из приложения Swing

Недавно я обновил свой компьютер до более мощного, с четырехъядерным процессором с гиперпотоком (i7), таким образом, появилось множество реальных concurrency. Теперь я иногда получаю следующую ошибку при выходе (System.exit(0)) приложения (с графическим интерфейсом Swing), которое я разрабатываю:

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)

Ну, учитывая, что это началось с более чем concurrency -изменимого оборудования, и оно связано с потоками, и это случается иногда, это, очевидно, какая-то вещь времени. Но проблема в том, что трассировка стека настолько коротка. Все, что у меня есть, это список выше. Он вообще не включает мой собственный код, поэтому несколько сложно догадаться, где ошибка.

Кто-нибудь испытал что-то подобное раньше? Любые идеи, как начать его решать?

Изменить: Поскольку выход из приложения Swing с System.exit(0) может быть "нечистым", но я не хочу, чтобы основной кадр был EXIT_ON_CLOSE, потому что я хочу убедиться, что ничего нет когда приложение завершает работу, я добавил механизм, чтобы он выполнял основной метод dispose() перед вызовом System.exit(0). Так что теперь это должно быть довольно чисто, но случайное исключение все же происходит. Это происходит после вызова 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 путем циклического перехода через массив Window.getWindows() (он содержит бездокументальный Dialog и т.д.), но это не имело никакого значения. Эта проблема, похоже, имеет мало общего с "чистотой" (т.е. Явным освобождением собственных ресурсов экрана перед выходом из игры). Это что-то еще, но что?

Изменить 2: Установка операции закрытия по умолчанию на EXIT_ON_CLOSE не имеет значения. http://www.google.com/search?q=sun.java2d.Disposer.run(Disposer.java:125) находит несколько отчетов об ошибках, так что, возможно, это действительно ошибка в реализации Sun Java2D. Я мог представить, что такие ошибки могут оставаться незафиксированными в течение длительного времени, потому что они практически безвредны на практике; исключение из крюка остановки вряд ли больно кому-либо еще. Учитывая, что это происходит в приложении GUI, исключение даже не замечается, если stderr не направлено на консоль или журнал.

4b9b3361

Ответ 1

Ваш Disposer заблокирован в вызове remove() (удаление родного ресурса следующей платформы). Это означает, что поток удаления (поток демона) не отключается естественным образом, когда VM выходит (что вы должны ожидать, так как вы завершаете его с помощью System.exit()).

В приложении есть поток не-демона, который удерживает виртуальную машину от выхода, когда были удалены все ваши окна.

Решение: найти его и заставить его выйти.

Обычно приложение качания выходит изящно, если все его окна поворота были удалены, например, эта программа выскочит из окна, а затем выйдет после его закрытия (все без вызова System.exit()):

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

Вы также можете попробовать запустить сборщик мусора перед выходом, просто для пинков.

Ответ 2

Если вы используете приложение swing, сначала вызовите System.gc(), а затем вызовите метод dispose(). Я думаю, что все будет хорошо. Я также использую это.

Хотелось бы проголосовать за это, но мне нужно больше репутации. Это решение сработало для меня, хотя я не могу найти объяснения, почему и мой коллега также говорит, что это бессмысленно.

У меня есть 1.7 и приложение swing, которое я создал, он читает в файле, перестраивает содержимое, а затем выводит его в файл. имеет кнопку запуска и выхода. использует предпочтения API, писатель, читатель и несколько других вещей. При открытии и закрытии приложения (без System.gc()) сразу всего два раза подряд возвращается это же Исключение, как указано выше. но с System.gc() прямо перед dispose() Я не могу снова получить исключение.

Ответ 3

System.exit(), вероятно, не самый чистый способ закрыть приложение на основе Swing

Невозможно установить основной кадр EXIT_ON_CLOSE:

mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE )

Затем установите его в невидимое?

Связанный Q здесь; System.exit(0) в java

Ответ 4

Интересно, не связано ли это с этой ошибкой:

Ошибка Java 6489540

В основном это означает, что если Java2D используется, когда существует объект InheritableThreadLocal или присутствует пользовательский contextClassLoader, они захватываются и постоянно вызывают утечку памяти и, возможно, такие странные блокировки.

Если это так, то обходным путем было бы инициировать действие Java2D в основном потоке (т.е. сразу же, когда приложение запускается), так что DisposerThread живет в среде "squeky clean". Он запускается статическим инициализатором, поэтому просто фиктивная загрузка ресурса java2d и его освобождение будет достаточно, чтобы получить DisposerThread, который не зависает на нежелательные вещи.

Ответ 5

Я думаю, что нашел, откуда исходит ошибка!

Когда у вас есть базовое java-приложение с подменю Exit в меню File... Существует ярлык для активации действия выхода... Этот ярлык должен сделать круговую ссылку или что-то в этом роде...

Существуют решения:

Прежде всего, это необязательно, чтобы все было ясно: Реализует этот интерфейс "WindowListener" из вашего главного окна.

При построении этого главного окна сделайте следующее:

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) {}

После этого вы должны быть осторожны с вашими ярлыками! Вам нужно удалить действие из меню выхода, чтобы управлять им с помощью 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
}

Я не объясняю, почему, но это работает для меня... Я думаю, что есть своего рода циркулярные ссылки... Надеюсь помочь тебе. См. Ya.

Ответ 6

У меня такая же проблема (Java 6). Я заметил поток unknwon sun.awt.image.ImageFetcher в отладчике. Я думаю, что это происходит от меня, используя JButtons с иконками. Поток ImageFetcher исчезает через 2 секунды. Если поток ImageFetcher не работает, моя программа выходит из строя.

Ответ 7

Похоже, что у вас есть поток, который не прекращается, когда вы уходите. Примечательно, что поток - wait() ing, и этот метод генерирует прерванное исключение, если вы пытаетесь остановить поток во время его работы. Я всегда задавал фоновые потоки для запуска как демоны, которые также могли бы помочь.

Я бы сделал следующее в вашем 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.

Ответ 8

Иногда возникают ошибки, но это работает нормально:

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);
}

Ответ 9

У меня была такая же проблема, и я обнаружил, что у меня только что был скрытый кадр в фоновом режиме (у меня была видимость, равная false). Если бы я не позвонил .dispose() на мой скрытый кадр, а затем .dispose() на моем mainFrame мне не нужно было звонить 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(); }
}

Ответ 10

Если вы использовали Swing App Framework, вы можете переопределить Application.exit() для выполнения очистки или добавить ExitListener, а также, В противном случае вы также можете добавить к своему приложению завершение работы, Runtime.getRuntime().addShutdownHook().

Ответ 11

Темы в java завершаются только тогда, когда все методы run() завершают выполнение. В противном случае вы всегда будете иметь эти расширенные объекты Thread в VM messing around. Перед выходом из приложения необходимо завершить все потоки.

Также подумайте, что при создании jFrame вы начинаете Thread (CURRENT_THREAD, я считаю)

Ответ 12

Я получал подобную ошибку, и как-то это сработало для меня:

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();
        }
    });
}

Ответ 13

Попробуйте использовать EventQueue.invokeLater(), чтобы закрыть Swing.

Ответ 14

Кажется, что ошибка была решена в Java 1.7.

Настроил мой Eclipse для запуска в jdk 1.7, и ошибка исчезла.

Йоав

Ответ 15

Я просто столкнулся с этой ошибкой, используя базы данных. Проблема заключалась в том, что соединение с базой данных не было закрыто. Я решил это, используя следующий код:

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

Просто выбросьте это для других людей...

Ответ 16

Попробуйте это. Это сработало для меня. Я создавал экземпляр JFileChooser, который не был правильно настроен после вызова System.exit(0).

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

Ответ 17

Если вы используете приложение swing, сначала вызовите System.gc(), а затем вызовите метод dispose(). Я думаю, что все будет хорошо. Я также использую это.