Por que Platform.runLater não verifica se está atualmente no thread JavaFX?
Pergunta
Ao usar JavaFX 8, precisamos executar interações com a GUI via Platform.runLater
, caso contrário, eles lançarão exceções se executados em outro thread.
Contudo a implementação de Platform.runLater
nunca verifica se está atualmente no thread JavaFX.
Eu escrevi o seguinte método:
public static void runSafe(final Runnable runnable) {
Objects.requireNonNull(runnable, "runnable");
if (Platform.isFxApplicationThread()) {
runnable.run();
}
else {
Platform.runLater(runnable);
}
}
Isso garante que ele nunca possa ser executado em um thread que não seja de aplicativo FX.
Existe alguma razão para que a implementação padrão não cause esse tipo de curto-circuito?
Solução
runLater
essencialmente coloca seu Runnable em uma fila para execução quando o thread FX estiver disponível.O método pode ser acessado por meio de threads não-FX.Imagine que alguns outros threads colocaram tarefas no runLater
fila e depois ligando runLater
novamente, seja do thread FX ou não, deve colocar a nova tarefa no final dessa fila.
Com o curto-circuito que você propõe, as tarefas anteriores teriam basicamente uma prioridade mais baixa, o que pode não ser desejável.
Outras dicas
Ao chamar uma função, e a função é chamada de 'runLater', espero que ela seja executada mais tarde, não agora.
Parece-me que a implementação está fazendo a coisa certa, com base no nome, e é documentação:
Execute o Runnable especificado no thread do aplicativo JavaFX em algum momento não especificado no futuro.
Este método, que pode ser chamado de qualquer thread, postará o Runnable em uma fila de eventos e retornará imediatamente ao chamador.Os Runnables são executados na ordem em que são postados.Um executável passado para o método runLater será executado antes de qualquer Runnable passado para uma chamada subsequente para runLater
Se você não quiser que o código seja executado mais tarde, não peça que ele seja executado mais tarde.Isso é o que você essencialmente fez com seu código.
Eu vi pessoas ligando EventQueue.invokeLater
do EDT em Swing ocasionalmente...é, segundo o cânone, uma técnica legítima.Portanto, esta é a mesma situação no JavaFX, a menos que eu esteja muito enganado.
Pessoalmente, tenho minhas dúvidas sobre essa técnica, no entanto.Ver essa questão:a resposta escolhida usa invokeLater
porque selectAll()
precisa que todos os eventos EDT atuais sejam concluídos antes de serem chamados:esta solução garante efectivamente que selectAll
não pode ser executado antes do outro código EDT acontecer aqui.
Mas esta resposta, afirmo, tem vulnerabilidades.Veja a resposta que sugeri (escrita em Jython, mas deve ser compreensível).Suponha que alguém defina “contagem de cliques para iniciar a edição” como 1.Suponhamos, o que é mais preocupante, que algo imprevisível aconteça entre o invokeLater
e a selectAll
.A menos que você tenha certeza absoluta de que não possui nenhum mecanismo alternativo, ou tenha certeza absoluta de que os eventos e objetos dos dois threads estão completamente "desacoplados", eu pessoalmente diria para evitar chamar runLater
do encadeamento JavaFX.
A simultaneidade está sempre esperando para morder você.Portanto, é melhor usar essas técnicas com extremo cuidado!