我有多个工作线程和一个 JavaFX GUI,它报告这些线程中发生的事情。
线程之间共享大量数据,需要可视化。所以我使用 ObservableList 和 Property 能够轻松地在 JavaFX 中显示数据。
我制作了一个小示例应用程序来展示与我的应用程序中发生的情况类似的内容。它有 2 个列表,工作线程将数据从一个列表移动到另一个列表。状态字符串保持最新。完整的示例代码可以在http://codetidy.com/6569/找到 (此代码会崩溃,见后文)
以下是共享的 ObservableList 的 & 属性:
private ObservableList<String> newItems;
private ObservableList<String> readyItems;
private StringProperty status;
以下是它们在 JavaFX 中的使用方式:
listViewA.setItems(processor.getNewItems());
listViewB.setItems(processor.getReadyItems());
statusLabel.textProperty().bind(processor.getStatus());
工作线程更新这些列表和属性,但当然,它需要在 JavaFX 线程上执行此操作,这就是事情变得丑陋的地方。如果我不必在 JavaFX 线程上更新,这将是代码:
Runnable newItemAdder = new Runnable() {
@Override
public void run() {
while(true) {
synchronized (newItems) {
String newItem = checkForNewItem(); //slow
if (newItem != null) {
newItems.add(newItem);
newItems.notify();
}
if (newItems.size() >= 5)
status.set("Overload");
else
status.set("OK");
}
synchronized (readyItems) {
if (readyItems.size() > 10)
readyItems.remove(0);
}
try { Thread.sleep(200); } catch (InterruptedException e) { return; }
}
}
};
new Thread(newItemAdder).start();
Runnable worker = new Runnable() {
@Override
public void run() {
while(true) {
List<String> toProcess = new ArrayList<String>();
synchronized (newItems) {
if (newItems.isEmpty())
try { newItems.wait(); } catch (InterruptedException e) { return; }
toProcess.addAll(newItems);
}
for (String item : toProcess) {
String processedItem = processItem(item); //slow
synchronized (readyItems) {
readyItems.add(processedItem);
}
}
}
}
};
new Thread(worker).start();
当然,有些事情很容易用 Platform.runLater 解决:
Platform.runLater(new Runnable() {
@Override
public void run() {
synchronized (newItems) {
if (newItems.size() >= 5)
status.set("Overload");
else
status.set("OK");
}
}
});
这对于我只在任务中写入并且只在 JavaFX GUI 中读取的属性/列表来说很好。但是对于这个例子中的列表,它变得非常复杂,您需要在其上同步、读取和写入。你需要添加很多 Platform.runLater 并且你需要阻塞直到“runLater”任务完成。这导致代码非常复杂且难以读写(我设法让这个示例以这种方式运行,看看我的意思:http ://codetidy.com/6570/ )。
还有其他方法可以使我的示例正常工作吗?我会很感激任何其他解决方案或部分解决方案......