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.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…