本文给出了一些使用SwingWorker类的例子。SwingWorker类的目的是实现一个后台线程,让你可以用它来执行一些费时的操作,而不影响你的程序的GUI的性能。关于SwingWorker类的一些基本信息,请参阅《线程和Swing》。
注意:在2000年9月我们修改了这篇文章和它的例子以适用于一个更新版本的SwingWorker类。SwingWorker类的这个版本修正了一些微妙的线程bug。
对执行一些费时或可阻塞操作的Swing程序来说,线程是基本的解决之道。例如,如果你的应用程序要根据用户选择的菜单项发出一个数据库请求或加载一个文件,那么你应该在一个单独的线程中完成这些工作。本文阐述了在一个分离的worker线程中完成上述工作的途径。
本文包括以下主要内容:
-
SwingWorker类:这一部分告诉你怎样下载SwingWorker类并描述了SwingWorker类的用途。介绍了SwingWorker类的interrupt()方法。
-
引入Worker线程的例子:演示一个运用SwingWorker类的应用程序。
-
例一:中断一个Swing Worker线程:解释如何运用interrupt()方法来中断worker线程。
-
例二:从Swing Worker线程反馈给用户:例一的增强,添加了一个模式对话框以提示用户输入。
概览:SwingWorker类
因为SwingWorker类并不是Java发行版的一部分,你需要下载和编译它才能使用。它的源代码在这里:
SwingWorker.java
SwingWorker类简介
SwingWorker类可以简单且方便地用于在一个新的线程中计算一个数值。要使用这个类,你只要创建一个SwingWorker的子类并覆盖SwingWorker.construct()方法来执行计算。然后你实例化它,并在这个新实例上调用start()方法。
例如,下面的代码片断中产生了一个线程,其中构造了一个字符串。然后,片断中使用了get()方法来取得前面由construct方法所返回的值,并且在必要时将等待。最后,在显示器上显示出字符串的值。
- SwingWorker worker = new SwingWorker() {
- public Object construct() {
- return "Hello" + " " + "World";
- }
- };
- worker.start();
-
System.out.println(worker.get().toString());
在实际的应用程序中,construct方法会做些更有用(但可能很费时)的事情。比如,它可能做下列工作之一:
- 执行大量的运算
- 执行可能导致大量的类被装载的代码
- 为网络或磁盘I/O阻塞
- 等待其他资源
在上面的代码片断中没有展示的一个SwingWorker类的特性是,当construct()返回后,SwingWorker可以让你在事件派发线程中执行一些代码。你可以通过覆盖SwingWorker的finished()方法来做到这一点。典型地,你可以用finished()来显示刚刚构造的一些组件或设置组件上显示的数据。
原始版本的SwingWorker类的一个局限是,一旦一个worker线程开始运行,你无法中断它。(译注:本文、本文的例子及SwingWorker类曾被更新。)不管怎么说,对于一个交互应用程序来说,让用户在工作线程完成前一直等待是相当糟糕的风格。如果用户希望终止一项正在执行中的操作,执行此操作的线程应该能够尽快中止。
使用interrupt()方法
在第二版的SwingWorker类中加入了一个interrupt()方法以允许中断一个线程。你的线程应该以下面两种途径之一得到中断的通知:
- 正在执行诸如sleep()或wait()方法的线程在interrupt()被调用时会抛出一个InterruptedException。
- 线程可以显式询问它是否已被中断,通过形如以下代码:
使用sleep()或wait()方法的工作线程(如后面例子中的线程)一般不需要显式检查是否被中断。通常让sleep()或wait()方法抛出InterruptedException就足够了。
不过,如果你希望能够中断一个不含定时循环的SwingWorker,还是需要用interrupted()方法来显式检查中断。
引入Worker线程的例子
本文余下的部分讨论一个包含两个worker线程的例子的程序。下图是程序主窗口的截图,和它弹出的一个对话框:
例子的源代码由以下文件组成:
你可以下载一个包含上面所有文件的zip文件。在此zip文件中还包含一个带有HTML格式的说明的例子,这个版本的例子更能说明问题(但也更复杂)。
运行此例子前要先编译:
/usr/local/java/jdk1.3.0/bin/javac ThreadsExample.java
用以下命令行运行此例子:
/usr/local/java/jdk1.3.0/bin/java ThreadsExample
当你按下“Start”按钮,相应例子的worker线程将被创建。你可以在进度条中查看它的进度。你可以按下“Cancel”按钮来中断worker线程。在启动例子二稍等几秒,你会看到一个对话框提示你确认是否执行。稍后我们再详述这个。
例子一:中断Swing Worker线程
接着我们要讨论的例子是Example1.java。这个例子中的worker线程包含一个执行100次的循环,并在两次循环之间睡眠半秒。
-
//progressBar maximum is NUMLOOPS (100) progressBar的最大值是NUMLOOPS (100)
-
for(int i = 0; i < NUMLOOPS; i++) {
- updateStatus(i);
- ...
- Thread.sleep(500);
- }
为了向你展示如何使用interrupt()方法,我们的例子程序可以让你启动一个SwingWorker然后等待它完成或者中断它。程序中的SwingWorker子类的construct()方法所作的唯一一件事就是调用Example1的doWork()方法。doWork()方法的完整源码列在下面。这个例子在处理worker线程时会重置进度条并把标签设为“Interrupted”。因为中断可能发生在sleep()方法调用之外,所以代码中在调用sleep()方法之前要先检查中断与否。
在此方法中执行的费时操作应该:周期性地让用户知道它有所进展。updateStatus()方法会为事件派发线程排队Runnable对象(记住:不要在其他线程中执行GUI工作)。一旦按下“Start”按钮,动作监听器(action listener)会创建SwingWorker,使得worker线程被创建。Worker线程启动后,它将执行它的construct()方法,该方法将调用doWork()(如下面的代码所示)。下面的代码例示了Example1实现的SwingWorker的子类。
- worker = new SwingWorker() {
- public Object construct() {
- return doWork();
- }
- public void finished() {
- startButton.setEnabled(true);
- interruptButton.setEnabled(false);
- statusField.setText(get().toString());
- }
- };
finished()方法在construct()方法返回后执行(即worker线程完成后)。它的任务只是简单地重新使“Start”按钮有效,同时使“Cancel”按钮无效,并将状态域显示的值设置成worker的计算结果。记住finished()方法是在事件派发线程中执行的,所以它可以安全地直接更新GUI。
例子二:从Worker线程提示用户
这个例子实现为Example1的子类。唯一的区别是,在worker线程执行了大约两秒后,它将阻塞直到用户响应一个Continue/Cancel模态对话框。如果用户选择的不是“Continue”,我们就退出doWork()循环。
这个例子演示了一个在许多worker线程中应用的惯用法:如果worker执行中到达一个不期望的状态,它将阻塞起来直到用户被提醒或用一个模态对话框从用户那里收集到了更多信息。这种做法有一点复杂,因为对话框的显示需要放到事件派发线程中,且worker线程需要被阻塞直到用户解除了该模式对话框。
我们使用SwingUtilities的invokeAndWait()方法来在事件派发线程中弹出对话框。与invokeLater()不同,invokeAndWait()会阻塞起来直到它的Runnable对象返回。在我们的例子中,Runnable对象直到对话框被解除才返回。我们创建一个内部Runnable类DoShowDialog,来完成弹出对话框。一个实例变量DoShowDialog.proceedConfirmed,被用来记录用户的选择:
-
class DoShowDialog implements Runnable {
- boolean proceedConfirmed;
- public void run() {
- Object[] options = {"Continue", "Cancel"};
- int n = JOptionPane.showOptionDialog
- (Example2.this,
- "Example2: Continue?",
- "Example2",
- JOptionPane.YES_NO_OPTION,
- OptionPane.QUESTION_MESSAGE,
- null,
- options,
- "Continue");
- proceedConfirmed =
- (n == JOptionPane.YES_OPTION);
- }
- }
因为showConfirmDialog()方法弹出一个模态对话框,调用会阻塞直到用户解除该对话框。
为了显示对话框并阻塞调用线程(worker线程)直到对话框被解除,worker线程调用invokeAndWait()方法,定义一个DoShowDialog的实例:
- DoShowDialog doShowDialog = new DoShowDialog();
-
try {
- SwingUtilities.invokeAndWait(doShowDialog);
- }
-
catch
- (java.lang.reflect.
- InvocationTargetException e) {
- e.printStackTrace();
- }
代码中捕获的InvocationTargetException是调试DoShowDialog的run()方法的残留。当invokeAndWait()方法返回后,worker线程可以读取doShowDialog.proceedConfirmed来获得用户的响应。
分享到:
相关推荐
标签:aspect-swing-worker-1.1.jar.zip,aspect,swing,worker,1.1,jar.zip包下载,依赖包
关于android图片失真的swing-work-1.1架包
第二篇文章《使用Swing Worker线程》,演示了如何使用SwingWorker线程工具类。它也可以在存档中找到。 本文介绍了修订过的SwingWorker类,并演示了和基于模型的组件(model-based components)如JTable和JTree同时...
worker-threads-pool:轻松管理Node.js工作线程池
用于《vue3中使用Web Worker多线程》这篇文章的项目Demo下载 文章地址:https://blog.csdn.net/weixin_42063951/article/details/125300644
用于《vue3中使用Web Worker多线程》这篇文章的项目Demo下载 文章地址:https://blog.csdn.net/weixin_42063951/article/details/125300644
react-native-workers, 后台服务和用于响应本机的网络工作者 react-native-workers在后台运行旋转工作线程并运行CPU密集型任务。 Android上的加分点:即使用户退出应用程序,也可以保持工作状态
# 使用方法: 解压 【***.jar中文文档.zip】,再解压其中的 【***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作...
serviceworker-webpack-plugin, 简化服务工作者的创建以服务 web pack分发包 serviceworker-webpack-plugin简化服务工作者的创建以服务 web pack分发包。 安装npm install serviceworker-webpack-plugin问题解
前端开源库-web-worker-manager网络工人经理,工人经理
在这里,我们有一个简单的Swing应用程序,现在需要添加一个耗时的任务,并且需要在运行时更新进度条。 当前解决方案完全在EDT上运行( AnalysisService类中100%打包),因此阻止进度条被更新/重新绘制。 我试图...
文中我们深度分析了线程池执行任务的核心流程,在ThreadPoolExecutor类的addWorker(Runnable, boolean)方法中,使用CAS安全的更新线程的数量之后,接下来就是创建新的Worker线程执行任务
支持Node.js环境的捆绑工人入门yarn add rollup-plugin-web-worker-loader --dev将插件添加到汇总配置中: import webWorkerLoader from 'rollup-plugin-web-worker-loader' ;export default { entry : 'src/index....
Laravel开发-laravel-worker-command Laravel 5的指挥装备员
前端开源库-worker-client-server工作客户端服务器,WorkerClient/WorkerServer
要使用worker-loader将Web Worker加载到NextJS站点上,并允许在其worker上运行babel等webpack加载器,必须覆盖构建输出路径。 感谢。 // next.config.jsmodule . exports = { webpack ( config , options ) { ...
为什么使用Worker线程? 1、不会阻塞主应用程序,但是fork进程一次只能处理一项任务。如果您有两个任务,一个将花费10秒,另一个将花费1秒,按照顺序执行,不理想的是必须等待10秒才能执行第二个任务。 2、如果一个...
webworker封装调用face-api.js
首先,您需要安装worker-loader : $ npm install worker-loader --save-dev 内联式 App.js import Worker from "worker-loader!./Worker.js" ; 设定档 webpack.config.js module . exports = { module : { ...