介绍

在第1部分中,我展示了如何在ZK应用程序中使用服务器推送和线程来执行后台任务。 但是,这个简单的示例具有一个重大缺陷,这使其对于实际应用程序而言是一种不好的方法:它为每个后台任务启动了一个新线程。

JDK5引入了ExecutorService类,该类抽象了线程详细信息,并为我们提供了一个不错的接口,可用于提交任务以进行后台处理。

在这篇博客文章中,我将描述创建ZK应用程序的最重要部分,该应用程序包含一个采用字符串并以大写形式返回的后台任务。 完整的示例项目可在Github上找到:

https://github.com/Gekkio/blog/tree/master/2012/10/async-zk-part-2

1.创建一个ExecutorService实例

首先,我们需要一个可以在ZK代码中使用的ExecutorService。 在大多数情况下,我们需要一个共享的单例实例,该实例可以通过依赖项注入(例如Spring)进行配置和管理。 确保只创建一次ExecutorService,并且使用应用程序将其正确关闭是非常重要的。

在这个示例项目中,我将使用一个简单的holder类,该类管理单个静态可用的ExecutorService实例的生命周期。 该持有人必须在zk.xml中配置为侦听器

package sample;import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;import org.zkoss.zk.ui.WebApp;
import org.zkoss.zk.ui.util.WebAppCleanup;
import org.zkoss.zk.ui.util.WebAppInit;public class SampleExecutorHolder implements WebAppInit, WebAppCleanup {private static volatile ExecutorService executor;public static ExecutorService getExecutor() {return executor;}@Overridepublic void cleanup(WebApp wapp) throws Exception {if (executor != null) {executor.shutdown();System.out.println('ExecutorService shut down');}}@Overridepublic void init(WebApp wapp) throws Exception {executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());System.out.println('Initialized an ExecutorService');}}

请注意,线程池是根据系统中的处理器使用固定大小配置的。 正确的线程池大小调整非常重要,并且取决于您打算执行的任务类型。 最大线程数也是同时进行的并发任务的最大数量!

2.编写对后台任务的结果进行建模的事件类

我们将使用ZK服务器推送将任务结果传达回UI,因此必须将结果建模为ZK事件。 创建自定义Event的子类而不是将结果添加到data参数中始终是一个好主意,因为自定义类更加类型安全并且可以支持多个字段。

第一个事件类表示任务仍在运行时发送的状态更新。 在此示例中,它将包含输入字符串中的字符数。

package sample;import org.zkoss.zk.ui.event.Event;public class FirstStepEvent extends Event {public final int amountOfCharacters;public FirstStepEvent(int amountOfCharacters) {super('onFirstStepCompleted', null);this.amountOfCharacters = amountOfCharacters;}}

第二个事件类表示完全完成的任务。 在此示例中,它包含大写的输入字符串。

package sample;import org.zkoss.zk.ui.event.Event;public class SecondStepEvent extends Event {public final String upperCaseResult;public SecondStepEvent(String upperCaseResult) {super('onSecondStepCompleted', null);this.upperCaseResult = upperCaseResult;}}

3.编写任务类

任务类应具有以下特征:

  • 它实现了Runnable
  • 它将所有必需的输入数据作为构造函数参数(如果可能,数据应该是不可变的!)。 此输入数据必须是线程安全的,并且通常不应包含任何与ZK相关的内容(无组件,会话等)。 例如,如果要使用文本框值作为输入,请事先读取该值,并且不要将文本框本身作为参数传递
  • 它需要一个Desktop,以及至少一个EventListener作为构造函数参数。 它们是将结果发送回UI所必需的

在此示例中,唯一的输入数据是将用于计算任务结果的字符串。

package sample;import java.util.Locale;import org.zkoss.zk.ui.Desktop;
import org.zkoss.zk.ui.DesktopUnavailableException;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;public class SampleTask implements Runnable {private final String input;private final Desktop desktop;private final EventListener<Event> eventListener;@SuppressWarnings({ 'rawtypes', 'unchecked' })public SampleTask(String input, Desktop desktop, EventListener eventListener) {this.input = input;this.desktop = desktop;this.eventListener = eventListener;}@Overridepublic void run() {try {// Step 1Thread.sleep(10000);Executions.schedule(desktop, eventListener, new FirstStepEvent(input.length()));// Step 2Thread.sleep(10000);Executions.schedule(desktop, eventListener, new SecondStepEvent(input.toUpperCase(Locale.ENGLISH)));} catch (DesktopUnavailableException e) {System.err.println('Desktop is no longer available: ' + desktop);} catch (InterruptedException e) {}}}

注意所有构造函数参数如何存储在私有的final字段中,以及输入数据如何不可变(Java中字符串是不可变的!)。 该任务通过使用Thread.sleep模拟长时间运行的处理,并在“处理”完成一半时提交状态事件。

4.在ZK作曲家中安排任务

在作曲家中使用任务非常简单。 您只需要启用服务器推送,并将新的任务实例提交给执行者。 一旦有可用的后台线程可用,它将自动启动任务。

desktop.enableServerPush(true);
// Get the executor from somewhere
executor = SampleExecutorHolder.getExecutor();
executor.execute(new SampleTask(input.getValue(), desktop, this));

在此示例中,编辑器扩展了GenericForwardComposer,该实现实现了EventListener,因此它本身可以处理产生的任务事件。 这两个事件均由使用状态信息更新UI的方法处理。

public void onFirstStepCompleted(FirstStepEvent event) {status.setValue('Task running: ' + event.amountOfCharacters + ' characters in input');
}public void onSecondStepCompleted(SecondStepEvent event) {status.setValue('Task finished: ' + event.upperCaseResult);
}

最后的话

使用此技术为ZK应用程序中的长期运行的任务添加强大的支持非常容易。 ZK编写器中的结果代码非常简单,因为结果是使用典型的Event / EventListener范例传递的,该范例在ZK应用程序中非常常见。

这种技术的最大危险是线程安全错误,这些错误很难调试。 完全了解执行每段代码的线程,并确保所有共享状态都是完全线程安全的,这至关重要。 只要后台任务本身不访问其他非线程安全资源,使用不可变的输入数据和不可变的输出事件通常足以确保安全。 一些常见的错误是:

  • 在后台任务中调用线程本地相关的库方法(例如,任何看起来神奇地获得某种“当前”值的方法)。 后台线程不会自动包含与servlet线程相同的线程本地值,因此默认情况下,所有这些方法都将失败。 例如ZK中的Sessions.getCurrent(),Executions.getCurrent()和许多Spring Security静态方法。
  • 将非线程安全参数传递给后台任务。 例如,传递一个可变的List,该可变的List可能在任务运行时由编写者修改(总是制作可变集合的副本!)。
  • 在事件中传递非线程安全的结果数据。 例如,在结果事件中传递列表,而稍后将在任务中修改列表(始终复制可变集合!)。
  • 在桌面中访问非线程安全的方法。 即使您可以在后台任务中访问桌面,大多数桌面方法也不是线程安全的。 例如,不能保证调用desktop.isAlive()能够正确返回状态(至少在ZK 6.5中,该方法依赖于非易失性字段,因此不能保证在后台线程中可见写入)

参考: Advanced ZK:异步UI更新和后台处理– Jawsy Solutions技术博客博客上的JCG合作伙伴 Joonas Javanainen的第二部分 。

翻译自: https://www.javacodegeeks.com/2012/10/advanced-zk-asynchronous-ui-updates-and-background-processing-part-2.html

高级ZK:异步UI更新和后台处理–第2部分相关推荐

  1. zk ui_高级ZK:异步UI更新和后台处理–第2部分

    zk ui 介绍 在第1部分中,我展示了如何在ZK应用程序中使用服务器推送和线程来执行后台任务. 但是,这个简单的示例具有一个重大缺陷,这使其对于实际应用程序而言是一种不好的方法:它为每个后台任务启动 ...

  2. zk ui_高级ZK:异步UI更新和后台处理–第1部分

    zk ui 异步UI更新非常有用,因为它们通常可以提高响应性,可用性和用户界面的总体感觉. 我将在这里重点介绍ZK框架,但是通常,相同的原理也适用于桌面UI(Swing,SWT). 长时间运行的处理 ...

  3. 高级ZK:异步UI更新和后台处理–第1部分

    异步UI更新非常有用,因为它们通常可以提高响应性,可用性和用户界面的总体感觉. 我将在这里重点介绍ZK框架,但是通常,相同的原理也适用于桌面UI(Swing,SWT). 长时间运行的处理 有时,您可能 ...

  4. WPF多线程UI更新

    前言 在WPF中,在使用多线程在后台进行计算限制的异步操作的时候,如果在后台线程中对UI进行了修改,则会出现一个错误:(调用线程无法访问此对象,因为另一个线程拥有该对象.)这是很常见的一个错误,一不小 ...

  5. WPF多线程UI更新——两种方法

    WPF多线程UI更新--两种方法 前言 在WPF中,在使用多线程在后台进行计算限制的异步操作的时候,如果在后台线程中对UI进行了修改,则会出现一个错误:(调用线程无法访问此对象,因为另一个线程拥有该对 ...

  6. ONLYOFFICE文档V7.2现已发布————插件市场、实时查看器、连写、全新表单字段、UI 更新等

    ONLYOFFICE文档V7.2现已发布 ----插件市场.实时查看器.连写.全新表单字段.UI 更新等 我们已在最新版本的在线编辑器中提供了多种实用性改进,比如:轻松的插件安装流程.实时查看器.支持 ...

  7. 网站服务器处理器计划怎么设置,系统属性-高级-处理器计划选程序还是后台.docx...

    系统属性-高级-处理器计划选程序还是后台 一.每天关机前要做的清洗: 双击"我的电脑"--右键点C盘--点"属性"--点"磁盘清理"--点& ...

  8. 最新ChatGPT网站源码/支持用户注册付费套餐/支持Ai绘画/支持用户会员套餐/邀请分佣功能/支持后台一键更新/网站后台管理/永久更新

    前言 ChatGPT 是一个基于 GPT-3.5/GPT-4 模型的对话系统,它主要用于处理自然语言对话.ChatGPT 虽然才发布几天时间,但是就已经火爆全网了.然后陆陆续续已经出现了各式版本,今天 ...

  9. (转)WTL入门(5)--- 高级的对话框UI类

    源代码:http://download.csdn.net/source/3522809 上一篇文章中,讲述了一些WTL的关于对话框和控件的特性,本章中将讲述的新的WTL类实现了一些高级UI特性:所有者 ...

最新文章

  1. Debian/Ubuntu 报错解决:Command 'ifconfig' not found, but can be installed with
  2. c语言约束函数,求解能不能用c或c++语言实现下面的约束条件
  3. 潘建伟团队最新研究成果登上Nature:首次实现1120公里长距离无中继纠缠量子密钥分发...
  4. rdcl 报表设置不分页
  5. 442. 数组中重复的数据
  6. SAP UI5框架绘制footer区域的入口调试
  7. LeetCode-Maximal Rectangle-最大矩形
  8. 大道至简java伪代码
  9. clover写入efi_Clover EFI bootloader for Mac(四叶草启动引导工具)
  10. Intellij idea的Dependencies和Libraries有什么区别 ??
  11. 【java集合框架源码剖析系列】java源码剖析之TreeSet
  12. 项目:任务清单(Vuex)
  13. arcgis 循环模型批量处理_科学网-ArcGIS模型构建器批处理操作-张凌的博文
  14. C语言实现 神奇魔方
  15. CDA备考学习笔记——基础知识篇(三)
  16. 图片在线预览html,Viewer.js – 强大的JS/jQuery图片查看器
  17. 手游挂机工作室 - 二三点科普
  18. 图解|什么是缓存系统三座大山
  19. 批量数据 导入数据库
  20. 023-zabbix性能优化中的几个中肯建议

热门文章

  1. 最小生成树——Prim(普利姆)算法
  2. java 堆转储快照_捕获Java堆转储的7个选项
  3. java中的可检查和不检查_检查Java测试中发生了什么
  4. aws lambda_跑来跑去:假人与AWS Lambda的第一次接触
  5. jvm运行时类加载机制_JVM体系结构:JVM类加载器和运行时数据区
  6. spark在服务器运行示例_创建示例HTTPS服务器以获取乐趣和收益
  7. java8 streams_Java SE 8新功能介绍:使用Streams API处理集合
  8. java与java ee_Java EE 8怎么了?
  9. jboss eap_HawtIO在JBoss EAP上(第二部分)
  10. play框架配置 拦截器_如何使用Play框架为https配置SSL证书