java - 当后台服务执行密集型任务时,如何防止 GUI 延迟?

标签 java concurrency javafx

我正在用 JavaFX 编写一个应用程序,它偶尔需要加载大约 1,000,000 行(或可能更多)的大型 CSV 文件。

当用户单击按钮开始加载文件时,服务将启动以加载内容,同时显示进度/取消对话框。 Service 中的 call() 方法基本上是一个 while 循环,它在每次迭代时从 CSV 文件加载另一行。

问题是当我启动服务时,进度条(不确定样式)变得不稳定。拖动对话框也是不稳定和滞后的。

我在网络上搜索解决方案时运气不佳,但我找到的最接近的方法是在循环中放置一个 Thread.sleep(),让 GC 等其他东西有机会 catch 。

这个解决方案似乎减少/消除了卡顿,但它会增加很多加载数据的时间。我还猜测不同处理器的确切 sleep 时间会有所不同。

有什么方法可以动态计算出 sleep 时间/频率?或者调用一些方法来阻塞足够长的时间以保持 GUI 响应?

我的服务代码:

public class CSVLoadingService extends Service<List<ObservableList<DoubleProperty>>> {
private ObjectProperty<File> srcFile = new SimpleObjectProperty<>();
private IntegerProperty startIndex = new SimpleIntegerProperty(0);
private ObjectProperty<Character> csvDelimeter = new SimpleObjectProperty(CSVParser.DEFAULT_SEPARATOR);
private DoubleProperty invalidCSVReplacement = new SimpleDoubleProperty(0);
private ObjectProperty<Dialog> dialog = new SimpleObjectProperty<>(null);

@Override
protected Task<List<ObservableList<DoubleProperty>>> createTask() {
    return new Task<List<ObservableList<DoubleProperty>>>() {
        final ObjectProperty<File> _srcFile = srcFile;
        final IntegerProperty _startIndex = startIndex;
        final ObjectProperty<Character> _csvDelimeter = csvDelimeter;
        final DoubleProperty _invalidCSVReplacement = invalidCSVReplacement;

        @Override
        protected ObservableList<ObservableList<DoubleProperty>> call() throws Exception {
            if (_startIndex.getValue() < 0)
                throw new IllegalArgumentException("Start index can't be negative.");
            if (_srcFile.getValue() == null)
                throw new IllegalStateException("File can't be null.");

            final ObservableList<ObservableList<DoubleProperty>> result = FXCollections.observableArrayList();

            // Read the data from the CSV file.
            try (final CSVReader reader = new CSVReader(new BufferedReader(new FileReader(_srcFile.getValue())),
                    _csvDelimeter.getValue(),
                    CSVParser.DEFAULT_QUOTE_CHARACTER,
                    _startIndex.getValue()))
            {
                // Read first line.
                String[] csvLine = reader.readNext();

                // If there is actually data, then read the rest of it.
                if (csvLine == null || csvLine.length == 0) {
                    result.clear();
                } else {
                    // Create columns.
                    for (String value : csvLine) {
                        result.add(FXCollections.observableArrayList());
                    }

                    // Parse the CSV reads and add them to the columns.
                    int iteration = 0;
                    do {
                        int i = 0;
                        for (String value : csvLine) {
                            // Convert the string to a number and add it to the column.
                            try {
                                result.get(i).add(new SimpleDoubleProperty(Double.parseDouble(value)));
                            } catch (NumberFormatException|NullPointerException e) {
                                result.get(i).add(_invalidCSVReplacement);
                            }
                        }

                        iteration++;
                    } while (!isCancelled() && null != (csvLine = reader.readNext()));
                }
            }

            return result;
        }
    };
}

@Override
protected void succeeded() {
    super.succeeded();

    if (dialog.getValue() != null) {
        dialog.getValue().close();
    }
}

@Override
protected void failed() {
    super.failed();

    if (dialog.getValue() != null) {
        dialog.getValue().close();
    }
}

最佳答案

这是使用线程优先级的典型场景。您希望 GUI 线程的优先级高于后台线程。

关于java - 当后台服务执行密集型任务时,如何防止 GUI 延迟?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32555783/

相关文章:

java - 无法从 Java 主应用程序运行两个 Java FX 实例?

Java 扫描器从输入文件中分离数据

java - ActionBar 刷新按钮

c++ - 在 C++ 中递增和递减全局变量时的竞争条件

python - 是否可以使用并发.futures 在事件发生后执行 tkinter 类内的函数/方法?如果是,怎么办?

java - 如何从具有重复条目的过滤列表中删除特定索引?

java - 任务未正确执行代码

java - 你的 SQL 语法错误在附近

java - 无法解析 FragmentPagerAdapter 的父类(super class)

java - 从调用线程运行 CompletableFuture.thenAccept ?