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

Я недавно обновил свой компьютер к более мощному, с четырехъядерным процессором (i7) гиперпоточности, таким образом много реального доступного параллелизма. Теперь я иногда получаю следующую ошибку при выходе (System.exit(0)) приложение (с GUI 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)

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

Кто-либо испытал что-то вроде этого прежде? Какие-либо идеи, как начать решать его?

Править: Начиная с выхода из приложения 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

Я даже пытался явно расположить все Windows цикличным выполнением через Window.getWindows() массив (это содержит бесхозный Dialogs и такой), но это не имело никакого значения. Эта проблема, кажется, имеет мало общего с "чистотой" (т.е. явно высвобождение собственных экранных средств прежде, чем выйти). Это - что-то еще, но что?

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

27
задан 11 revs 23 May 2010 в 05:32
поделиться

6 ответов

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

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

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

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

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

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

15
ответ дан 28 November 2019 в 05:43
поделиться

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

Вы не можете установить свой основной фрейм на EXIT_ON_CLOSE:

mainFrame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE )

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

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

2
ответ дан 28 November 2019 в 05:43
поделиться

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

0
ответ дан 28 November 2019 в 05:43
поделиться

Похоже, что у вас запущен поток, который не завершился, когда вы вышли. Примечательно, что поток выполняет функцию 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();
  }
});

Выходя вручную из цикла, вы позволяете методу ожидания завершиться (надеюсь, вы не ждете очень долго, не так ли? Если да, то, возможно, вам стоит пересмотреть то, как вы используете свои потоки), а затем доберетесь до точки в коде, где безопасно прерваться - безопасно, потому что вы закодировали это так - и тогда поток завершится, позволяя приложению завершиться просто отлично.

Обновление. Возможно, вы где-то неправильно используете поток диспетчера событий, и он ждет/продолжает работать, когда вы пытаетесь выйти? Диспетчерский поток должен делать как можно меньше работы, а все сложное передавать другому потоку так быстро, как только может. Я признаю, что я немного копаюсь в темноте, но я склонен думать, что это не ошибка, особенно учитывая, что вы начали замечать это на более мощной машине - что для меня кричит "Race Condition!", а не ошибка Java.

1
ответ дан 28 November 2019 в 05:43
поделиться

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

Ошибка Java 6489540

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

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

2
ответ дан 28 November 2019 в 05:43
поделиться

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

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

0
ответ дан 28 November 2019 в 05:43
поделиться