Javafx:javafx.concurent 和 Platform.runLater 之间的区别? [英] Javafx: Difference between javafx.concurent and Platform.runLater?

查看:31
本文介绍了Javafx:javafx.concurent 和 Platform.runLater 之间的区别?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很好奇 javafx.concurent 和 Platform.runLater 在多线程 JavaFx 编程中到底有什么区别.

这是否意味着使用 javafx.concurrent,我们可以有多个实际的绘图线程,还是最终都在一个线程上?

例如,我喜欢的一件事是同时使用 JavafX 和 swing,因为它们都使用了 2 个不同的绘图线程.我会使用 Swing 处理繁重的内容(例如打开 FileChooser),并使用 JavaFX 处理核心视觉内容,例如播放无缝的循环视频.但是,由于无头异常错误,mac 使这变得不可能,所以一切都落在 javafx 上,这意味着在执行打开文件选择器等操作时会出现很多暂停.

如果我使用 javafx.concurrent 重写我的应用程序,我是否可以像我曾经使用 Swing + JavaFX 那样从本质上模仿 2 个绘制线程体验?

解决方案

Platform.runLater

WorkerPlatform.runLater 的补充.

  • 当您在 JavaFX 应用程序线程之外执行并且想要在 JavaFX 应用程序线程上运行一些逻辑时,请使用 Platform.runLater.
  • 当您在 JavaFX 应用程序线程上运行并希望在新线程上生成一些逻辑或(尤其是)I/O 时,请使用 Worker,这样您就不会阻塞JavaFX 应用线程.

您永远不会想在 Platform.runLaterrun 方法中进行网络 I/O,但通常希望在 Worker 中进行call 方法.

任务和服务

考虑使用 TaskService 工人.这些是 FutureTask(反过来是一个可运行).Worker 提供了一个 call 方法来在后台线程.它们维护执行状态(向 JavaFX 线程提供线程安全回调通知状态更改)并通过value返回调用结果,消息异常 属性.

利用 TaskService javadoc 示例中的设计模式来简化线程安全应用程序的创建,并具有以下特性:

  • 异步获取数据以更新 UI.
  • 任务进度的定期消息更新.
  • 构建尚未附加到显示场景的节点图.
  • 通过进度条等监控进度

同时使用 Workers 和 Platform.runLater

此外,TaskService 的使用与 Platform.runLater 的使用并非不兼容.例如,如果您有一个很长时间运行的 Task,您希望定期或在缓冲区填满时将部分结果返回到 UI,然后执行 Platform.runLater任务的 call 方法就是这样做的方法.

使用现有线程系统

当您没有由库提供的现有线程服务,而是创建自己的线程以在后台执行时,Worker 会很有用.如果您有现有的线程服务,则需要使用 Platform.runLater 在 JavaFX 应用程序线程上执行逻辑.

小心编写多线程代码

请注意,即使您使用 Worker,您仍然需要知道自己在做什么.您仍然必须注意不要违反标准的 JavaFX 并发规则,例如永远不要更新活动场景图中的节点(包括不更新活动场景图中的节点绑定到的值 - 例如 items 支持 ListView).

回答您的一些附加问题

<块引用>

这是否意味着使用 javafx.concurrent,我们可以有多个实际的绘图线程,还是最终都在一个线程上?

JavaFX 中只有一个渲染线程.您不能使用 JavaFX 并发创建更多渲染线程.您可以执行诸如在 JavaFX 线程之外创建节点或使用多个线程将像素设置为屏幕外 WriteableImage 或 Canvas 之类的操作,但最终每个渲染操作都会通过由 JavaFX 系统管理的单个线程,而您无法对其进行控制.

<块引用>

如果我使用 javafx.concurrent 重写我的应用程序,我是否可以像我曾经使用 Swing + JavaFX 那样从本质上模仿 2 个绘制线程体验?

没有.即使可以,我也不认为这是可取的.使用这样的模型,很容易产生微妙的、难以调试的线程处理相关错误.您可能会从这种设置中看到的收益可能比您希望或预期的要少.

请参阅有关为什么可能不建议使用 2 个或更多绘制线程"的相关文章:

Java 8 正在添加一个实验性的命令行开关,以便为 JavaFX 应用程序线程和 Swing 事件调度线程使用相同的线程.这样做的主要原因是它简化了编程模型.

<块引用>

一切都落在 javafx 上,这意味着在打开文件选择器之类的操作时会出现很多停顿.

也许您的代码效率低下(例如在 UI 线程上执行 I/O)导致了暂停.

<块引用>

繁重的工作(例如打开 FileChooser)

打开和渲染 FileChooser 并不繁重.JavaFX 可以轻松处理此类操作,而不会降低性能.可能耗时的是与 I/O 相关的内容,例如递归遍历大型文件树以获取文件属性.在这种情况下,您可以做的是为在 Worker 中运行的 I/O 生成一个线程,并通过 Platform.runLater 定期将部分结果反馈给 UI 线程.这样的方案会运作良好.瓶颈不是绘图,因此使用另一个绘图线程没有任何优势.瓶颈是缓慢的 I/O 系统,这个瓶颈是通过使用单独的 I/O 线程来缓解的,这样主 UI 线程不会受到影响,并且用户在 I/O 发生时不会遇到 UI 冻结.

I'm curious as to what exactly the difference is between javafx.concurent and Platform.runLater for multithreaded JavaFx programming.

Does it mean that with javafx.concurrent, we can have multiple actual drawing threads or does it all end up on one thread anyway?

E.g One thing I enjoyed was using JavafX and swing concurrently as they both used 2 different drawing threads. I would use swing for the heavy stuff (e.g. opening a FileChooser) and use JavaFX for the core visual stuff e.g playing a seamless, looping video. However, the mac makes this impossible because of that headless exception error so everything fell on javafx and that meant a lot of pauses when doing things like opening filechoosers.

If I rewrite my app With javafx.concurrent, could I essentially mimic that 2 draw thread experience as I once did with Swing + JavaFX?

解决方案

Platform.runLater

A Worker is complementary to Platform.runLater.

  • Use Platform.runLater when you are executing off of the JavaFX Application Thread and you want to run some logic on the JavaFX application Thread.
  • Use a Worker when you are running on the JavaFX Application Thread and want to spawn some logic or (especially) I/O on a new thread so that you don't block the JavaFX Application Thread.

You would never want to do network I/O inside a Platform.runLater's run method, but would often want to do it in a Worker's call method.

Task and Service

Consider using the Task or Service subclasses of Worker. These are JavaFX wrappers for FutureTask (which is in turn a Runnable). Workers provide a call method to run logic on a background thread. They maintain execution status (with thread safe callback notification to the JavaFX thread for state changes) and return results of the call via value, message and exception properties.

Take advantage of the design patterns in the Task and Service javadoc examples to simplify creation of thread-safe applications with features such as:

  • Asynchronous fetching of data for UI update.
  • Periodic message updates for task progress.
  • Constructing Node graphs which are not yet attached to a displayed scene.
  • Monitoring progress via progress bars, etc.

Using Workers and Platform.runLater together

Also, usage of Task and Service is not incompatible with use of Platform.runLater. For instance, if you have a very long running Task from which you want to return partial results to the UI periodically or as a buffer fills, then executing Platform.runLater in the task's call method is the way to do that.

Working with existing threading systems

Workers are useful when you don't have an existing threaded service provided by a library, but are instead creating your own threads to execute in the background. If you have an existing threaded service, then you will need to use Platform.runLater to perform logic on the JavaFX application thread.

Be careful writing multi-threaded code

Note that you still need to know what you are doing, even if you use a Worker. You must still take care that you don't violate standard JavaFX concurrency rules, such as never updating Nodes on the active scene graph (including not updating values that Nodes in the active scene graph are bound to - such as the observable list of items backing a ListView).

Answering some of your addition questions

Does it mean that with javafx.concurrent, we can have multiple actual drawing threads or does it all end up on one thread anyway?

There is only one render thread in JavaFX. You cannot make more render threads using JavaFX concurrent. You can do things like create nodes off the JavaFX thread or set pixels to an off screen WriteableImage or Canvas using many threads, but eventually every render operation passes through a single thread managed by the JavaFX system over which you have no control.

If I rewrite my app With javafx.concurrent, could I essentially mimic that 2 draw thread experience as I once did with Swing + JavaFX?

No. Even if you could, I don't think it would be advisable. With such a model it is far too easy to create subtle, hard to debug thread processing related errors. And the gain you might see from such a setup may be less than you may wish for or expect.

See related articles on why having 2 or more "draw threads" is likely inadvisable:

Java 8 is adding an experimental command line switch to use the same thread for the JavaFX application thread and the Swing event dispatch thread. The main reason for this is that it simplifies the programming model.

everything fell on javafx and that meant a lot of pauses when doing things like opening filechoosers.

Perhaps there were inefficiencies in your code (such as performing I/O on the UI thread) which caused the pauses.

the heavy stuff (e.g. opening a FileChooser)

Opening and rendering a FileChooser is not heavy. JavaFX can easily handle such an operation without a performance degradation. What can be time consuming is stuff related to I/O, for example walking a large file tree recursively to get file attributes. What you can do in such cases is spawn a thread for the I/O run it in a Worker and periodically feed back partial results to the UI thread via Platform.runLater. Such a scheme will work well. The bottleneck is not the drawing, so having another drawing thread provides no advantage. The bottleneck is the slow I/O system and this bottleneck is mitagated by the using a separate thread for I/O so that the main UI thread is not impacted and the user does not experience UI freezes while I/O is occurring.

这篇关于Javafx:javafx.concurent 和 Platform.runLater 之间的区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆