Случайное прерывание Исключения при выходе из приложения 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
не направлено на консоль или журнал.
Ответы
Ответ 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().
Я думаю, что все будет хорошо. Я также использую это.