message属性被设计为保存任务的“当前消息”的属性:即,目标用例类似于状态消息.在这个用例中,是否永远不会截获存储在属性中的消息只是非常短暂的时间并不重要.的确,documentation for updateMessage()表示:
Calls to updateMessage are coalesced and run later on the FX
application thread,so calls to updateMessage,even from the FX
Application thread,may not necessarily result in immediate updates to
this property,and intermediate message values may be coalesced to
save on event notifications.
(我的重点).因此,简而言之,传递给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 task = new Task() {
@Override
public String call() {
// in real life,do real work here...
return "\n" + value ; // value to be processed in onSucceeded
}
};
task.setOnSucceeded(e -> ta_Statusbereich.appendText(task.getValue()));
exec.execute(task);
}
如果您想从单个任务完成所有这些操作并控制顺序,那么您可以将所有消息放入BlockingQueue,从阻塞队列中获取消息并将它们放在FX Application线程的文本区域中.为了确保不会使用过多的调用来泛洪FX应用程序线程,您应该每帧渲染一次消息来自队列的消息不超过一次呈现给屏幕.您可以使用AnimationTimer来实现此目的:保证每帧渲染时调用一次handle方法.这看起来像:
BlockingQueue messageQueue = new LinkedBlockingQueue<>();
Task task = new Task() {
@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++) {
// do real work...
messageQueue.put(Integer.toString(i));
}
return null ;
}
};
new Thread(task).start(); // or submit to an executor...
// ...
public class MessageConsumer extends AnimationTimer {
private final BlockingQueue messageQueue ;
private final TextArea textArea ;
private final numMessages ;
private int messagesReceived = 0 ;
public MessageConsumer(BlockingQueue messageQueue,TextArea textArea,int numMessages) {
this.messageQueue = messageQueue ;
this.textArea = textArea ;
this.numMessages = numMessages ;
}
@Override
public void handle(long now) {
List messages = new ArrayList<>();
messagesReceived += messageQueue.drainTo(messages);
messages.forEach(msg -> textArea.appendText("\n"+msg));
if (messagesReceived >= numMessages) {
stop();
}
}
}