gpt4 book ai didi

JavaFX 应用程序线程变慢然后卡住

转载 作者:塔克拉玛干 更新时间:2023-11-01 22:47:21 29 4
gpt4 key购买 nike

我有一个多线程 JavaFX 应用程序。我有一堆后台线程正在调用此方法以从应用程序线程更新主 UI。

public void writeToActivityLog(String message){

class ThreadedTask implements Runnable {

private String message;

public ThreadedTask(String message){
this.message = message;
}

@Override
public void run() {
try{
//delete older text when there are more than 200 lines and append new text

String text = outputLog.getText();
String[] lines = text.split("\r\n");
String newText = "";
for(int i = 0; i < lines.length; i++){
if(i >= 200 || lines.length < 200){
newText += lines[i];
}
}
outputLog.setText(newText);
outputLog.appendText(message + "\r\n");

//scroll to the bottom of the log
outputLog.setScrollTop(Double.MIN_VALUE);

} catch(NullPointerException e){
e.printStackTrace();
}
}
}

ThreadedTask thread = new ThreadedTask(message);
Platform.runLater(thread);

}

一开始,这个方法很管用。但是进入程序几秒钟后,它开始变慢,几秒钟后整个 UI 卡住并停止响应用户输入(但它不会触发 Windows“此程序未响应”对话框)。但是,查看应用程序日志文件和我的 IDE 控制台,后台线程仍在执行并且似乎运行良好。

对于可以排队的 Platform.runLater() 请求的数量是否有一些限制?或者有什么方法可能会导致内存泄漏导致主应用程序线程终止但对后台线程没有任何作用?我对多线程编程还是很陌生,所以我不知道该想些什么。

我也知道 JavaFX 有另一个称为服务的并发工具,但我找不到任何关于何时以及为什么我应该使用它们而不是 Platform.runLater() 的解释。我编写过其他 JavaFX 应用程序,使用 Platform.runLater() 时从未遇到过任何问题。

编辑:

非常感谢下面的两个答案。问题不在于 JavaFX 或线程本身,而在于普通的错误代码。这是固定代码,为了完成:

public void writeToActivityLog(String message){
//Create a new thread to update the UI so that it doesn't freeze due to concurrency issues
class ThreadedTask implements Runnable {

private String message;

public ThreadedTask(String message){
this.message = message;
}

@Override
public void run() {
outputLog.setText(message);

//scroll to the bottom of the log
outputLog.setScrollTop(Double.MIN_VALUE);
}
}

String wholeMessage = new StringBuilder().append(outputLog.getText()).append(message).toString();
//modify the text of the output log so that it is 200 lines or less
StringBuilder newText = new StringBuilder();
String[] lines = wholeMessage.split("\r\n");

for (int i=Math.max(0, lines.length - 200); i<lines.length; i++) {
newText.append(new StringBuilder().append(lines[i]).append("\r\n").toString());
}

ThreadedTask thread = new ThreadedTask(newText.toString());
Platform.runLater(thread);
}

最佳答案

一些建议。

首先,这只是一般的 Java 事情,在这样的循环中通过串联来构建 String 是一个非常糟糕的主意。在许多情况下,现代编译器会为您修复此问题,但其中的 if 子句使得这样做更难,并且您不太可能自动获得此优化。您应该进行以下修改:

// String newText = "" ;
StringBuilder newText = new StringBuilder();
// ...
// newText += lines[i] ;
newText.append(lines[i]);
// ...
// outputLog.setText(newText);
outputLog.setText(newText.toString());

第二点是 JavaFX 并发问题。在这里创建线程并没有真正节省任何东西,因为您只是创建线程,然后通过将其直接传递给 Platform.runLater(...) 来安排它在 FX 应用程序线程上运行。因此,无论如何,整个 run() 方法只是在 FX 应用程序线程上执行。 (您的代码中没有后台线程!)

有两条规则需要遵守:1. 仅更新 FX 应用程序线程上的“Activity ”节点2. 不要在该线程上执行任何长时间运行的任务

javafx.concurrency 中的 Task 类是一个 Runnable(实际上是一个 Callable,更灵活一点),它提供了一些有用的生命周期方法,保证在 FX Application Thread 上运行。因此,您可以使用 Task 来计算新的日志文本,返回新的日志文本,然后在完成后使用 setOnSucceeded(..) 更新 UI。这看起来像:

class UpdateLogTask extends Task<String> { // a Task<T> has a call() method returning a T
private final String currentLog ;
private final String message ;
public UpdateLogTask(String currentLog, String message) {
this.currentLog = currentLog ;
this.message = message ;
}
@Override
public String call() throws Exception {
String[] lines = currentLog.split("\r\n");
StringBuilder text = new StringBuilder();
for (int i=0; i<lines.length; i++) {
if (i>=200 || lines.length < 200) {
text.append(lines[i]);
}
}
text.append(message).append("\r\n");
return text.toString() ;
}
}
final Task<String> updateLogTask = new UpdateLogTask(outputLog.getText(), message);
updateLogTask.setOnSucceeded(new EventHandler<WorkerStateEvenet>() {
@Override
public void handle(WorkerStateEvent event) {
outputLog.setText(updateLogTask.getValue());
}
});
Thread t = new Thread(updateLogTask);
t.setDaemon(true); // will terminate if JavaFX runtime terminates
t.start();

最后,我认为如果您想要最后 200 行文本,那么您的逻辑是错误的。尝试

for (int i=Math.max(0, lines.length - 200); i<lines.length; i++) {
text.append(lines[i]);
}

关于JavaFX 应用程序线程变慢然后卡住,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20577410/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com