Limitar las actualizaciones de javafx gui

Recibo objetos de datos en momentos aleatorios a una frecuencia alta, y necesito actualizar la GUI de JavaFX con estos. Sin embargo, no quiero llenar la cola de eventos de javafx con una gran cantidad de ejecutables (utilizo Platform.RunLater).

He estado pensando en cómo implementar mejor un algoritmo de aceleración.

  • ¿Sería mejor tener un hilo GUIUpdater separado que compruebe, por ejemplo, una cola de locking para objetos nuevos, y luego duerma, por ejemplo, durante 30 ms y luego vuelva a verificar, en un bucle infinito? En ese caso, ¿sería una cola de locking la estructura de datos óptima? Tenga en cuenta que solo necesito el último objeto de datos y la QueryQueue es una cola FIFO y parece que no puedo elegir solo la última entrada.
  • O bien, ¿sería mejor simplemente actualizar la GUI con Platform.RunLater si nanoTime-startTime> 30ms? En ese caso, no necesito un hilo separado para realizar la Platform.RunLater-call. Sin embargo, si se recibe una actualización cuando 30ms no han pasado, y luego no se reciben actualizaciones por algún tiempo, la última actualización no aparecerá en la GUI.

¿Alguna sugerencia sobre cómo diseñar un algoritmo de aceleración para JavaFX Platform.RunLater GUI actualizaciones de una manera corta y eficiente?

Este es el modismo utilizado en la clase Task para implementar el updateMessage(...) y otros métodos similares. Proporciona una solución agradable y robusta para evitar inundar el hilo de la aplicación FX:

 import java.util.concurrent.atomic.AtomicLong; import javafx.application.Application; import javafx.application.Platform; import javafx.geometry.Insets; import javafx.geometry.Pos; import javafx.scene.Scene; import javafx.scene.control.Label; import javafx.scene.layout.VBox; import javafx.stage.Stage; public class ThrottlingCounter extends Application { @Override public void start(Stage primaryStage) { final AtomicLong counter = new AtomicLong(-1); final Label label = new Label(); final Thread countThread = new Thread(new Runnable() { @Override public void run() { long count = 0 ; while (true) { count++ ; if (counter.getAndSet(count) == -1) { updateUI(counter, label); } } } }); countThread.setDaemon(true); countThread.start(); VBox root = new VBox(); root.getChildren().add(label); root.setPadding(new Insets(5)); root.setAlignment(Pos.CENTER); Scene scene = new Scene(root, 150, 100); primaryStage.setScene(scene); primaryStage.show(); } private void updateUI(final AtomicLong counter, final Label label) { Platform.runLater(new Runnable() { @Override public void run() { final String msg = String.format("Count: %,d", counter.getAndSet(-1)); label.setText(msg); } }); } public static void main(String[] args) { launch(args); } } 

AtomicLong contiene el valor actual que se utilizará para actualizar la etiqueta. El conteo aumenta y actualiza continuamente el AtomicLong , pero solo planifica una llamada a Platform.runLater(...) si su valor actual es -1. Platform.runLater(...) actualiza la Label con el valor actual de AtomicLong y voltea AtomicLong a -1, lo que indica que está listo para una nueva actualización.

El efecto aquí es progtwigr nuevas llamadas a Platform.runLater(...) siempre que el subproceso de la aplicación FX esté listo para manejarlas. No hay un intervalo de tiempo codificado que pueda necesitar ajuste.