簡體   English   中英

JavaFX8背景線程仍然會干擾GUI

[英]JavaFX8 Background Thread still interferes with GUI

我想編寫一個JavaFX GUI,該加載和解析一個較大的文件(22M)大約需要30秒。 但是,當我在Task中開始解析時,其余的GUI卻反應遲鈍。 但是,它並不是完全沒有響應,但仍會不時地掛起幾秒鍾。 為了證明這一點,我編寫了一個小應用程序,在進度條中顯示了解析的進度,並並行執行另一個任務,該任務僅每秒更新一次標簽。 現在,第二個任務不應被第一個任務阻止,因此我可能做錯了。 這是代碼:

每秒滴答滴答的任務:

class TimeTask extends Task<Void> {
    @Override
    protected Void call() throws Exception {
        while (true) {
            updateMessage(Instant.now().toString());
            Thread.sleep(1000);
        }
    }
}

用於解析日志文件的替換:從解析器以100ms的步長調用update方法。

public class ParseLogfileTask extends Task<Void> {

private LinkedList<Integer> numbers = new LinkedList<Integer>();
private Random random = new Random();

@Override
protected Void call() {
    Instant startInstant = Instant.now();
    while (Duration.between(startInstant, Instant.now()).getSeconds() < 25) {
        for (int i = 0; i < 10000000; i++) {
            numbers.add((Integer) random.nextInt());
        }
        Collections.shuffle(numbers);
        Collections.sort(numbers);
        numbers.clear();
        updateParseProgress(
                (int) Duration.between(startInstant, Instant.now())
                        .toMillis(), 25000);
    }
    return null;
}

public void updateParseProgress(int currentIndex, int maxIndex) {
    updateProgress(currentIndex, maxIndex);
}

}

應用程序的啟動方法:

@Override
public void start(Stage primaryStage) {
    try {
        Group root = new Group();
        Scene scene = new Scene(root, 400, 400);
        VBox vbox = new VBox();
        vbox.setAlignment(Pos.CENTER);
        ProgressBar bar = new ProgressBar();
        Label label = new Label("new");
        vbox.getChildren().addAll(bar, label);
        root.getChildren().add(vbox);
        primaryStage.setScene(scene);
        primaryStage.show();

        Task<Void> timeTask = new TimeTask();
        Task<Void> logFileTask = new ParseLogfileTask();
        bar.progressProperty().bind(logFileTask.progressProperty());
        label.textProperty().bind(timeTask.messageProperty());
        Platform.runLater(() -> {
            new Thread(timeTask).start();
            new Thread(logFileTask).start();
        });
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

編輯:我刪除了timeTask開始后5秒鍾的睡眠。 對於真正的問題,這不是必需的。 真正的問題是,只要logfileTask正在運行,timeTask不會每秒更新一次標簽。 僅每1-5秒更新一次。 一旦logfileTask完成,timeTask就會完全按照原樣更新標簽。 這可能與線程優先級有關嗎? logfileTask產生了很大的負擔...

編輯2:我無法通過使用其他方式來創建負載來重現該問題。 我只有ANTLR創建的解析器有這些問題,解析器創建了一個巨大的解析樹(許多對象)。 但是,由於解析器是在后台線程中啟動的,它如何干擾JavaFX Application線程?

編輯3:看起來確實是垃圾回收。 我將日志文件解析替換為生成大量數字,對其進行排序並再次將其丟棄,從而看到了與運行解析器時相同的差距(不是經常出現,但是影響更大)

您在ParseLogfileTask中調用的許多操作有很多方法。 就像一陣子(真)。 在返回null之前使用Thread.sleep。

@Override
protected Void call() {
    Instant startInstant = Instant.now();
    while (Duration.between(startInstant, Instant.now()).getSeconds() < 25) {
        for (int i = 0; i < 100000; i++) {
            numbers.add((Integer) random.nextInt());
        }
        Collections.shuffle(numbers);
        Collections.sort(numbers);
        numbers.clear();
        updateParseProgress(
                (int) Duration.between(startInstant, Instant.now())
                .toMillis(), 25000);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException ex) {

        }
    }
    return null;
}

所以對我有用。

此外,最好使用

ExecutorService service = Executors.newFixedThreadPool(2); service.execute(timeTask); service.execute(logFileTask);

用於調用您的線程。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM