Занятый цикл в другом потоке задерживает обработку EDT
У меня есть Java-программа, которая выполняет жесткий цикл в отдельном (не EDT) потоке. Хотя я думаю, что пользовательский интерфейс Swing должен быть отзывчивым, это не так. Пример программы ниже показывает проблему: нажатие кнопки «Попробовать меня» должно вызвать диалог более или менее спустя полсекунды, и должна быть возможность немедленно закрыть это диалоговое окно, щелкнув любой из его ответов. Вместо этого диалоговое окно занимает намного больше времени и / или закрывается после нажатия одной из кнопок.
Проблема возникает в Linux (на двух разных машинах с разными дистрибутивами), в Windows, на Raspberry Pi (только для серверной виртуальной машины) и в Mac OS X (сообщается другим пользователем SO).Java версии 1.8.0_65 и 1.8.0_72 (пробовал оба)Процессор i7 со многими ядрами. У EDT должно быть достаточно свободной вычислительной мощности.Кто-нибудь имеет какие-либо идеи, почему обработка EDT задерживается, хотя существует только один занятый поток?
(Обратите внимание, что, несмотря на различные предложенияThread.sleep
вызов является причиной проблемы, это не так. Это может быть удалено, и проблема все еще может быть воспроизведена, хотя она проявляется немного реже и обычно демонстрирует второе поведение, описанное выше - то есть не реагирующееJOptionPane
диалог, а не задержка появления диалога. Кроме того, нет причины, по которой вызов сна должен уступать другому потоку, потому чтоесть запасные ядра процессора как уже упоминалось выше; EDT может продолжать работать на другом ядре после вызоваsleep
).
import java.awt.EventQueue;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class MFrame extends JFrame
{
public static void main(String[] args)
{
EventQueue.invokeLater(() -> {
new MFrame();
});
}
public MFrame()
{
JButton tryme = new JButton("Try me!");
tryme.addActionListener((e) -> {
Thread t = new Thread(() -> {
int a = 4;
for (int i = 0; i < 100000; i++) {
for (int j = 0; j < 100000; j++) {
a *= (i + j);
a += 7;
}
}
System.out.println("a = " + a);
});
t.start();
// Sleep to give the other thread a chance to get going.
// (Included because it provokes the problem more reliably,
// but not necessary; issue still occurs without sleep call).
try {
Thread.sleep(500);
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
// Now display a dialog
JOptionPane.showConfirmDialog(null, "You should see this immediately");
});
getContentPane().add(tryme);
pack();
setVisible(true);
}
}
Обновить: Проблема возникает только с сервером ВМ (но смотрите дальнейшее обновление). Указание клиентской ВМ (-client
аргумент командной строки для исполняемого файла Java), кажется, подавляет проблему (обновление 2) на одной машине а не на другой.
Обновление 3: После нажатия на кнопку я вижу 200% -ное использование процессора процессом Java, подразумевая, что 2 полностью загруженных ядра процессора. Это не имеет смысла для меня вообще.
Обновление 4: Также происходит в Windows.
Обновление 5: Использование отладчика (Eclipse) оказывается проблематичным; кажется, что отладчик не может остановить потоки. Это весьма необычно, и я подозреваю, что в виртуальной машине существуют какие-то условия livelock или гонки, поэтому я подал ошибку в Oracle (обзор ID JI-9029194).
Обновление 6: я нашелмой отчет об ошибках в базе данных ошибок OpenJDK, (Мне не сообщили, что это было принято, я должен был искать это). Дискуссия там наиболее интересна и уже проливает некоторый свет на то, что может быть причиной этой проблемы.