Throttling javafx gui updates
This is the idiom used in the Task
class for implementing the updateMessage(...)
method, and other similar methods. It provides a nice, robust solution to avoid flooding the FX Application Thread:
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); }}
The AtomicLong
holds the current value to be used to update the Label. The count continually increments and updates the AtomicLong
, but only schedules a call to Platform.runLater(...)
if it's current value is -1. The Platform.runLater(...)
updates the Label
with the current value from the AtomicLong
and flips the AtomicLong
back to -1, indicating that it's ready for a new update.
The effect here is to schedule new calls to Platform.runLater(...)
whenever the FX Application Thread is ready to handle them. There's no hard-coded time interval which could need tuning.