我有多个工作线程和一个 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/)。
还有其他方法可以使我的示例正常工作吗?我将不胜感激任何其他解决方案或部分解决方案......
最佳答案
背景信息
Task javadoc包括许多并发使用模式,用于在 JavaFX 中的线程之间传递数据。
Task包括方便的数据传输方法,例如 updateMessage并且可以使用用户定义的状态属性代替您的 Runnable。
在适当的时候,考虑使用为并发设计的集合结构,例如 BlockingQueue .另一个优点是 BlockingQueues 可以有大小限制,这似乎是您想要的。
一些一般性建议
以上只是经验法则,不需要在教学上遵循。
相当复杂的线程示例
关于java - JavaFX 中的复杂并发 : using ObservableLists and Properties from multiple worker threads,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18530493/