Loop ocupado em outro thread atrasa o processamento do EDT
Eu tenho um programa Java que executa um loop apertado em um segmento separado (não EDT). Embora eu ache que a interface do usuário do Swing ainda deva responder, não é. O programa de exemplo abaixo mostra o problema: clicar no botão "Experimente" deve aparecer uma caixa de diálogo mais ou menos meio segundo depois, e deve ser possível fechar a caixa de diálogo imediatamente clicando em qualquer uma de suas respostas. Em vez disso, a caixa de diálogo leva muito mais tempo para aparecer e / ou leva muito tempo para fechar após clicar em um dos botões.
O problema ocorre no Linux (duas máquinas diferentes com distribuições diferentes), no Windows, no Raspberry Pi (somente VM do servidor) e no Mac OS X (relatado por outro usuário do SO).Java versão 1.8.0_65 e 1.8.0_72 (tentei ambos)Processador i7 com muitos núcleos. O EDT deve ter bastante poder de processamento disponível.Alguém tem alguma idéia de por que o processamento do EDT está sendo atrasado, mesmo que haja apenas um único segmento ocupado?
(Observe que, apesar das várias sugestões doThread.sleep
chamada sendo a causa do problema, não é. Ele pode ser removido e o problema ainda pode ser reproduzido, embora se manifeste um pouco menos frequentemente e geralmente exiba o segundo comportamento descrito acima - ou seja, não responsivoJOptionPane
caixa de diálogo em vez de aparência atrasada da caixa de diálogo. Além disso, não há razão para que a chamada de suspensão ceda ao outro encadeamento porqueexistem núcleos de processador sobressalentes como acima mencionado; o EDT poderia continuar funcionando em outro núcleo após a chamada parasleep
)
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);
}
}
Atualizar: O problema ocorre apenas com a VM do servidor (mas veja mais atualizações) Especificando a VM do cliente (-client
argumento da linha de comando para o executável java) parece suprimir o problema (atualização 2) em uma máquina, mas não em outra.
Atualização 3: Vejo 200% de uso do processador pelo processo Java depois de clicar no botão, o que implica que existem 2 núcleos de processador totalmente carregados. Isso não faz sentido para mim.
Atualização 4: Também ocorre no Windows.
Atualização 5: O uso de um depurador (Eclipse) é problemático; o depurador parece incapaz de parar os threads. Isso é altamente incomum e eu suspeito que haja algum tipo de livelock ou condição de corrida na VM, então eu registrei um bug no Oracle (ID de revisão JI-9029194).
Atualização 6: eu encontreimeu relatório de bug no banco de dados de erros do OpenJDK. (Não fui informado de que havia sido aceito, tive que procurá-lo). A discussão é mais interessante e já lança alguma luz sobre o que pode ser a causa desse problema.