我有一个多线程的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);
}
一开始,这个方法表现得很好。但是几秒钟后,程序开始变慢,再过几秒钟整个用户界面就会冻结并停止响应用户输入(但不会触发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);
}
ThreadedTask
的频率是多少?过于频繁调用Platform.runLater()
可能会导致问题。每秒排队和执行数百个Runnables
并不是一个好的建议。 - denhackl