有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java JavaFX TextArea追加高CPU使用率的文本

我正在开发一个JavaFX终端应用程序,它可以高速显示来自串行端口的文本。我正在使用TextArea控件来显示和管理文本。在来自串行端口的每个文本块上,我使用appendText函数将文本添加到终端。在将文本更新到TextArea时,我遇到性能问题(CPU使用率高)。下面的代码模拟了这个问题,CPU使用率从15%上升到30%,这在简单的文本更新中相当高:

public class Main extends Application {
    ExecutorService executor = Executors.newFixedThreadPool(1);
    @Override
    public void start(Stage primaryStage) {
        AnchorPane root = new AnchorPane();
        TextArea textArea = new TextArea();
        AnchorPane.setTopAnchor(textArea, 0.0);
        AnchorPane.setBottomAnchor(textArea, 0.0);
        AnchorPane.setLeftAnchor(textArea, 0.0);
        AnchorPane.setRightAnchor(textArea, 0.0);
        root.getChildren().add(textArea);
        textArea.setCache(true);
        textArea.setCacheShape(true);
        textArea.setCacheHint(CacheHint.SPEED);
        Runnable runnableTask = () -> {
            while (true) {
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Platform.runLater(() -> {
                    textArea.appendText("The easiest way to create ExecutorService is to use one of the factory methods\n");
                    while(textArea.getText().split("\n", -1).length > 500) {
                        int firstLineEndIndex = textArea.getText().indexOf("\n");
                        textArea.replaceText(0, firstLineEndIndex+1, "");
                    }
                });
            }
        };
        primaryStage.setTitle("TextArea performance");
        primaryStage.setScene(new Scene(root, 1000, 800));
        primaryStage.show();
        executor.execute(runnableTask);
    }
    public static void main(String[] args) {
        launch(args);
    }
}

有人能解释为什么CPU使用率这么高吗?有没有办法减少它? 谢谢**


共 (1) 个答案

  1. # 1 楼答案

    首先,你每秒做这些事情20次。这不是小事

    其次,你做的不仅仅是添加文本。对于runLater方法中的while循环的每次迭代,您都会对TextArea的整个文本反复调用split。正则表达式是昂贵的操作。这里有一种更有效的方法将文本限制在最后500行:

    String text = textArea.getText();
    String[] lines = text.split("\n", -1);
    if (lines.length > 500) {
        lines = Arrays.copyOfRange(lines,
            lines.length - 500, lines.length);
        text = String.join("\n", lines);
        textArea.setText(text);
    }
    

    与CPU问题无关,您编写了一个恶意线程:它忽略中断。中断是其他代码对线程发出的一个显式请求,要求它停止正在执行的操作并优雅地退出。有一种非常简单的方法:将while循环放入try块中:

    try {
        while (true) {
            Thread.sleep(50);
            Platform.runLater(() -> {
                textArea.appendText("The easiest way to create ExecutorService is to use one of the factory methods\n");
                // etc.
            });
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    

    或者,由于您使用的是ExecutorService而不是简单的Executor,因此可以创建可调用而不是可运行的,并使用ExecutorService.submit而不是execute,因此根本不需要try/catch:

    Callable<Void> runnableTask = () -> {
        while (true) {
            Thread.sleep(50);
            Platform.runLater(() -> {
                // ...
            });
        }
    };
    
    // ...
    
    executor.submit(runnableTask);