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

时间:2015-09-14 00:14:54

标签: java concurrency javafx

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

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

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

我在网上寻找解决方案并没有好运,但我发现最接近的是将Thread.sleep()置于循环中,让GC等其他东西有机会赶上来。

此解决方案似乎减少/消除了口吃,但它会增加大量时间来加载数据。我也猜测不同处理器之间的确切睡眠时间会有所不同。

有没有办法动态计算出多久/经常睡觉?或者调用一些方法,这些方法会阻塞足够长的时间来保持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();
    }
}

0 个答案:

没有答案