长时间运行的处理
有时,您可能需要进行数据库查询,或者需要很长时间才能进行外部Web服务调用。 通常,这些作业是同步的,因此基本上在代码中有一个特定的点,系统将必须等待结果并阻塞运行该代码的线程。 如果最终在UI线程中运行了这样的代码,则通常会完全阻塞UI。
实时更新
有时您不预先知道应该更新UI中的某些内容的确切时间。 例如,您可以使用一个可视仪表来显示应用程序中的用户数量。 当新用户进入应用程序时,应尽快更新当前用户的UI,以反映新用户数。 您可以使用基于计时器的机制来连续检查用户数量是否已更改,但是如果同时存在的用户过多,则即使UI中没有实际更新的内容,连续检查也将导致非常重的负载。
基本概念
让我们首先摘录此博客文章的标题:“异步UI更新和后台处理”
后台处理
在长时间运行的处理用例中,减少UI阻塞的最明显方法是将昂贵的处理从UI线程转移到某些后台线程。 能够理解哪种线程将在应用程序的不同部分中运行代码非常重要。 例如,在ZK应用程序中,大多数代码由servlet线程执行,这些线程基本上是与UI线程等效的servlet世界。 为了在某些后台线程中执行代码,我们需要一个线程池。 最简单的方法是使用JDK5中引入的java.util.concurrent.ExecutorService。 我们可以将Runnable对象推送到ExecutorService,因此我们基本上是在要求ExecutorService在某些后台线程中运行特定的代码块。
绝对关键的是,使用ThreadLocals的框架会遇到这种方法的问题,因为在servlet线程中设置的ThreadLocals在后台线程中将不可见。 一个示例是Spring Security,默认情况下使用ThreadLocal来存储安全上下文(=用户身份+其他东西)。
异步UI更新
在这种情况下,异步UI更新意味着什么? 基本上,这个想法是,一旦我们有了一些要在UI中呈现的信息,我们就会通知UI新数据(=异步),而不是直接在后台线程中更新UI(=同步)。 我们无法事先知道新信息何时可用,因此我们无法从客户端请求信息(除非我们使用昂贵的轮询)。
服务器推送ZK
使用ZK,基本上,有两种不同的方法可以在后台线程获得新信息后用于更新UI。 名称“服务器推送”来自以下事实:服务器具有一些必须推送到客户端的新数据,而不是典型的工作流程(客户端向服务器询问信息)。 首先,可以通过使用Executions.activate / deactivate抢占对桌面的独占访问权限来进行同步更新。 我个人不建议这样做,因为一旦您拥有独占访问权,UI线程将不得不等待直到停用桌面。 这就是为什么我在这篇博客文章中根本不会介绍这种方法的原因。
另一方面,异步更新是通过使用Executions.schedule完成的,它符合常规事件处理的Event / EventListener模型。 这个想法是,我们可以将普通的ZK Event对象推送到EventListeners,客户端将被告知这些事件。 之后,ZK使用Javascript进行正常的AJAX请求,事件将由EventListeners处理。 这意味着,如果我们使用异步更新,则所有实际的事件处理将由Servlet线程完成,并且所有ThreadLocals照常可用。 这使编程模型非常简单,因为您只需要普通的事件侦听器方法,而无需复杂的并发编程。
这是一个小例子:
public class TestComposer extends GenericForwardComposer {private Textbox search;public void onClick$startButton() {if (desktop.isServerPushEnabled()) {desktop.enableServerPush(true);}final String searchString = search.getValue();final EventListener el = this; // All GenericForwardComposers are also EventListeners// Don't do this in a real-world application. Use thread pools instead.Thread backgroundThread = new Thread() {public void run() {// In this part of code the ThreadLocals ARE NOT available// You must NOT touch any ZK related things (e.g. components, desktops)// If you need some information from ZK, you need to get them before this code// For example here I've read searchString from a textbox, so I can use the searchString variable without problemsString result = ... // Retrieve the result from somewhereExecutions.schedule(desktop, el, new Event('onNewData', null, result));}};backgroundThread.start();}public void onNewData(Event event) {// In this part of code the ThreadLocals ARE availableString result = (String) event.getData();// Do something with result. You can touch any ZK stuff freely, just like when a normal event is posted.}
}
在下一部分中,我将向您展示如何使用JDK5 ExecutorServices来运行任务而无需手动创建线程。 如果您真的想了解ZK服务器推送,还应该阅读相关的ZK文档 。
祝您编程愉快,别忘了分享!
参考: Advanced ZK:异步UI更新和后台处理– Jawsy Solutions技术博客博客上的JCG合作伙伴 Joonas Javanainen的第1部分 。
翻译自: https://www.javacodegeeks.com/2012/09/advanced-zk-asynchronous-ui-updates-and.html