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

zk ui

介绍

在第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静态方法。
  • 将非线程安全参数传递给后台任务。 例如,传递一个可变的列表,该可变的列表可能会在任务运行时由编写者修改(总是制作可变集合的副本!)。
  • 在事件中传递非线程安全的结果数据。 例如,在结果事件中传递列表,而稍后将在任务中修改列表(始终创建可变集合的副本!)。
  • 在桌面中访问非线程安全的方法。 即使您可以在后台任务中访问桌面,大多数桌面方法也不是线程安全的。 例如,不能保证调用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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351201.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学生管理系统 数据库版结果 查询student表中所有学生信息

1.创建school_java数据库 CREATE DATABASE schooljava; USE schooljava; CREATE TABLE student ( id INT(11), name VARCHAR(25), tel INT(11), sex VARCHAR(6) ); DESC student; java代码 package Mysql; import java.sql.Connection; import java.sql.DriverManager; imp…

如何查看思科交换机的出厂时间?

1.在交换机命令行运行show version 查看交换机的sn码 System serial number : FOC1723W0VP 2.SN码取出第四位至七位 以 FOC1723W0VP 为例 第四和第五位代表年份&#xff0c;第六和第七位代表当年的第XX周 &#xff08;范围是01至52周&#xff09; 1719962013 ; 23周 (注&…

Linux系统电脑非正常关机之后可能出现在登录界面循环的情况

Linux系统电脑非正常关机之后可能出现在登录界面循环的情况 例如&#xff1a; Ubuntu 18.04 有时会出现在登录界面循环&#xff0c;你输入密码&#xff0c;回车后又回到输入密码界面 &#xff0c;遇到这样的解决办法是直接进入命令行模式&#xff0c;然后看一下home文件夹&…

使用Spring Cloud Stream与RabbitMQ集成

在我以前的文章中&#xff0c;我写了两个系统之间非常简单的集成场景-一个生成一个工作单元&#xff0c;另一个处理该工作单元&#xff0c;以及Spring Integration如何使这种集成非常容易。 在这里&#xff0c;我将演示如何使用Spring Cloud Stream进一步简化此集成方案 我在…

ubuntu18.0.4 不能下载 libgd2-dev(ubuntu 20.04 安装perl 中GD 模块失败的解决办法)

ubuntu18.0.4 不能下载 libgd2-dev 一、错误信息&#xff1a; Unable to locate package libgd2-dev二、原因 没有对应源 到 https://packages.ubuntu.com/找对应名称 三、解决 18.04之后没有libgd2-dev sudo apt-get install libgd-dev参考&#xff1a;https://www.cnblo…

开课博客

自我介绍 对于自我介绍这篇我还是很意外的&#xff0c;个人信息不说了&#xff0c;说说自己的情况吧&#xff0c;当时大一的时候&#xff0c;感觉还是很喜欢编程的&#xff0c;个人感觉老师也挺喜欢我&#xff0c;可能大一下的时候心思多了点&#xff0c;慢慢的就没放多少心思在…

抓到一只苍蝇 writeup

题目在 http://ctf.idf.cn/index.php?ggame&marticle&aindex&id57 下载到的文件是misc_fly.pcapng&#xff0c;使用wireshark打开&#xff0c;能看到一堆tcp、http和dns协议混合的数据包&#xff0c;在上面的框里面输入http&#xff0c;让它只显示http协议的数据包…

ubuntu 20.04 安装circos

不需要自己手动按照&#xff0c;调配置 直接 sudo apt install circos一步到位

java环境变量的配置和使用

在downloads中选择JAVA DOWNLOAD进入Java下载列表 点选Accept License Agreement&#xff0c;选择Windows这一栏下载安装包 进入文件夹&#xff0c;双击应用程序根据提示进行安装&#xff0c;直至安装完成。 测试jdk是否安装成功&#xff0c;可在【开始】中搜索cmd&#xff…

perl 安装GD 出错解决方案

perl 安装GD 出错具体如下 install GD Running install for module GD Checksum for /root/.cpan/sources/authors/id/R/RU/RURBAN/GD-2.73.tar.gz ok Configuring R/RU/RURBAN/GD-2.73.tar.gz with Makefile.PL Package gdlib was not found in the pkg-config sea…

C语言学习一个月后感想

C语言学习一个月后感想 感谢李晓东老板及计算机工程师联盟的学长学姐和某神秘同级同学的辛勤指导&#xff0c;感谢宋雨田的督促和陪伴。 初识C的1、、体会 我本以为凭借瓜皮思维和花里胡哨操作可以让我熟练地学习语言&#xff0c;现在发现只是python的易入门给我的错觉。。。错…

使用Java 8处理并行数据库流

什么是并行数据库流&#xff1f; 阅读这篇文章&#xff0c;了解如何使用并行流和Speedment并行处理数据库中的数据。 在许多情况下&#xff0c;并行流可能比通常的顺序流快得多。 随着Java 8的引入&#xff0c;我们得到了期待已久的Stream库。 流的优点之一是使流并行非常容易…

idf实验室--简单编程字符统计

idf实验室--简单编程字符统计&#xff0c;有需要的朋友可以参考下。 第一眼看这道题很简单&#xff0c;不就是字符统计么&#xff0c;可是题目要求2s内回答&#xff0c;而且每次打开的页面需要统计的字符串内容都会变&#xff0c;这就蛋疼了&#xff0c;于是乎上网学习下如何提…

微服务(一) --- 架构与选型

微服务架构的概述 应用架构的发展 应用是可以独立运行的程序代码,提供相对完善的业务功能. 目前的软件架构有三种架构类型: 业务架构应用架构技术架构他们之间的甚是: 业务架构决定应用架构,技术架构支撑着应用架构. 应用架构的发展历程: 单体架构: 最古老的单体应用,没有任何应…

linux常见致命错误(fatal error),解决办法:

常见错误一&#xff1a;fatal error: zlib.h: No such file or directory 解决办法&#xff1a; sudo apt-get install zlib1g-dev 常见错误二&#xff1a;fatal error: curses.h: No such file or directory #include <curses.h> 解决办法&#xff1a;sudo apt-get i…

brainfu*k语言执行

输入&#xff1a; brainfu*k 代码&#xff1a; [>>>><<<<-]>.>....>.<<.>..------.--------.>.>. 程序&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXL 1000 /*…

Linux连接Windows服务器以及文件传输方法

最近&#xff0c;由于自身需要将操作系统换为Linux&#xff08;Ubuntu&#xff09;系统&#xff0c;但是由于实验室服务器为Windows系统&#xff0c;需要在Linux上连接Windows服务器&#xff0c;方法如下&#xff1a; 首先安装rdesktop 安装方法&#xff1a; sudo apt-get ins…

Filter过滤要登录的页面(重要)

一、为什么要写过滤器&#xff0c;过滤页面&#xff1f; 本人做了一个网站&#xff0c;目前还在开发。做过滤器的目的就是为了要过滤一些页面必需要用户登录之后才能看&#xff0c;主页什么的可以随便看&#xff0c;一旦涉及到要发布或评论什么信息&#xff0c;就必须要过滤用户…

mybatis crud_MyBatis教程– CRUD操作和映射关系–第1部分

mybatis crudCRUD操作 MyBatis是一个SQL Mapper工具&#xff0c;与直接使用JDBC相比&#xff0c;它极大地简化了数据库编程。 步骤1&#xff1a;创建一个Maven项目并配置MyBatis依赖项。 <project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/20…

C语言实现字符串匹配KMP算法

相信很多人&#xff08;包括自己&#xff09;初识KMP算法的时候始终是丈二和尚摸不着头脑&#xff0c;要么完全不知所云&#xff0c;要么看不懂书上的解释&#xff0c;要么自己觉得好像心里了解KMP算法的意思&#xff0c;却说不出个究竟&#xff0c;所谓知其然不知其所以然是也…