message
属性被设计成一个保存“当前消息”的属性,用于
task
:即目标用例类似于状态消息。在这种情况下,如果仅在该属性中存储了一条消息并且没有被截获,则不会产生影响。实际上,
updateMessage() 的文档 表明:
对 updateMessage 的调用将被合并并稍后在 FX 应用程序线程上运行,因此,即使从 FX 应用程序线程调用 updateMessage,也可能不一定会立即更新此属性,而是可以合并中间的消息值以节省事件通知。
(我强调)。因此,简言之,如果某些传递给 updateMessage(...)
的值很快就被另一个值取代,那么它们可能永远不会被设置为 messageProperty
的值。通常情况下,在每次渲染到屏幕时(每秒 60 次或更少),您可以期望观察到只有一个值。如果您有一个用例需要观察每个值,则需要使用另一种机制。
一个非常天真的实现方式是仅使用 Platform.runLater(...)
并直接更新文本区域。我不建议使用此实现方式,因为您可能会冒着向 FX 应用程序线程发送太多调用的风险(这正是 updateMessage(...)
合并调用的确切原因),从而使 UI 不响应。但是,此实现方式将如下所示:
for (int i = 1 ; i <= 300; i++) {
String value = "\n" + i ;
Platform.runLater(() -> ta_Statusbereich.appendText(value));
}
另一种选择是将每个操作作为单独的任务,并在某个执行器中并行执行它们。在每个任务的 onSucceeded
处理程序中将其附加到文本区域。在这种实现中,结果的顺序是不确定的,因此如果顺序很重要,则这不是一个合适的机制:
final int numThreads = 8 ;
Executor exec = Executors.newFixedThreadPool(numThreads, runnable -> {
Thread t = Executors.defaultThreadFactory().newThread(runnable);
t.setDaemon(true);
return t ;
});
for (int i = 1; i <= 300; i++) {
int value = i ;
Task<String> task = new Task<String>() {
@Override
public String call() {
return "\n" + value ;
}
};
task.setOnSucceeded(e -> ta_Statusbereich.appendText(task.getValue()));
exec.execute(task);
}
如果您想通过单个任务来完成所有工作,并控制顺序,那么您可以将所有消息放入一个
BlockingQueue
中,在FX应用程序线程上从阻塞队列获取消息,并将其放置在文本区域中。为了确保不会过多调用FX应用程序线程,您应该每帧渲染屏幕时最多从队列中使用一次消息。您可以使用
AnimationTimer
来实现这一目的:它的
handle
方法保证每帧渲染都会被调用。示例如下:
BlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
Task<Void> task = new Task<Void>() {
@Override
public Void call() throws Exception {
final int numMessages = 300 ;
Platform.runLater(() -> new MessageConsumer(messageQueue, ta_Statusbereich, numMessages).start());
for (int i = 1; i <= numMessages; i++) {
messageQueue.put(Integer.toString(i));
}
return null ;
}
};
new Thread(task).start();
public class MessageConsumer extends AnimationTimer {
private final BlockingQueue<String> messageQueue ;
private final TextArea textArea ;
private final numMessages ;
private int messagesReceived = 0 ;
public MessageConsumer(BlockingQueue<String> messageQueue, TextArea textArea, int numMessages) {
this.messageQueue = messageQueue ;
this.textArea = textArea ;
this.numMessages = numMessages ;
}
@Override
public void handle(long now) {
List<String> messages = new ArrayList<>();
messagesReceived += messageQueue.drainTo(messages);
messages.forEach(msg -> textArea.appendText("\n"+msg));
if (messagesReceived >= numMessages) {
stop();
}
}
}