没有合适的资源?快使用搜索试试~ 我知道了~
北京火龙果软件工程技术中心原文来自java.sun.com作者:JosephBowbeer本文并不属于任何系列,但它是TheSwingConnection中发表的第三篇关于在Swing中使用线程的文章。第一篇文章《线程与Swing》,解释了Swing的单线程规则。这篇文章现在可以在TheSwingConnectionArchive找到。第二篇文章《使用SwingWorker线程》,演示了如何使用SwingWorker线程工具类。它也可以在存档中找到。本文介绍了修订过的SwingWorker类,并演示了和基于模型的组件(model-basedcomponents)如JTable和JTree同时使
资源推荐
资源详情
资源评论
Swing线程的最后讨论线程的最后讨论--利用异步模型利用异步模型
原文来自java.sun.com
作者:作者:Joseph Bowbeer
本文并不属于任何系列,但它是The Swing Connection中发表的第三篇关于在Swing中使用线程的文章。
第一篇文章《线程与Swing》,解释了Swing的单线程规则。这篇文章现在可以在The Swing Connection Archive找到。
第二篇文章《使用Swing Worker线程》,演示了如何使用SwingWorker线程工具类。它也可以在存档中找到。
本文介绍了修订过的SwingWorker类,并演示了和基于模型的组件(model-based components)如JTable和JTree同时使用线
程。
要理解本文呈现的材料,熟悉SwingWorker和JTable和JTree组件会有所帮助。你可以在存档索引中找到关于JTable和JTree的
文章。
本文分为下面几个主要部分:
介绍和回顾
动态树
远程树
SwingWorker修订版
下载
结论
参考资料
关于作者
---------------------------------------------------------------------------
介绍与回顾介绍与回顾
在钻研树、表和异步模型之前,我首先回顾一下Swing的单线程规则(single-thread rule)并检验它的含义。
Swing的单线程规则是说,的单线程规则是说,Swing组件在某一时刻仅能被一个线程访问。组件在某一时刻仅能被一个线程访问。这个规则对gets和sets都有效,并且“一个线程”通常指
的都是事件派发线程。
单线程规则应用于UI组件是非常相称的,因为UI组件往往都以单线程方式使用,并由用户发起大多数动作。构建线程安全的组
件是困难而冗长乏味的:如果能避免则最好不过。但除了它的好处,单线程规则有更多的含义。
Swing组件所有的事件都在事件派发线程(event-dispatch thread)中发送和接收,除此之外才不遵守单线程规则。例如,属性
变更事件(property-change events)应该在事件派发线程中发送,模型变更事件(model-change events)应该在事件派发线
程中接收。
对于基于模型的组件如JTable和JTree来说,单线程规则意味着仅能在事件派发线程中访问模型本身。出于这个理由,模型中
的方法必须执行得很快并且决不能阻塞,否则整个用户界面会响应迟钝。
但想象一下你有一个带但想象一下你有一个带TreeModel的的JTree要访问一个远程服务器?要访问一个远程服务器?你会发现当服务器不可用或过于繁忙时,你对的TreeModel
的调用会阻塞,并使得整个用户界面被冻结。你能做些什么来改进界面的响应能力?
再假设你有一个带再假设你有一个带TableModel的的JTable管理着网络上的一个设备?管理着网络上的一个设备?你会发现当被管理的设备繁忙或网络拥挤时,界面变得迟
钝。你该怎么办?
这些困难的情况在召唤线程。当需求浮现,我们还是有几种途径在Swing中使用线程,尽管存在单线程规则。
本文展现了两种方法来使用线程访问缓慢的、远程的或其他异步的模型,并显示了如何在JTree和JTable组件中使用。(不仅
仅由事件派发线程访问的模型被称为“异步”模型。)
-----------------------------------------------------------------------------
动态树动态树
假设你有一个带TreeModel的JTree要访问远程服务器,但服务器又是缓慢或不可靠的,你该怎么办?
DynamicTree演示了如何使用后台线程动态展开JTree的节点。
图1是正在处理节点展开的DynamicTree。
图1
分裂模型(分裂模型(Split-model)设计)设计
DynamicTree基于一种分裂模型设计(split-model design)。在这个设计中,真正的模型是一个异步模型,它可能是缓慢或不
可靠的。JTree模型使用一个标准的同步模型来维持一个真正的模型的snapshot。(异步模型可能位于远程服务器,出于这个
原因我通常称之为远程模型,并且我把Swing组件的模型称为本地模型。)
使用本地模型来影射或缓存远程模型有助于提供一个在所有时刻都可靠的、高响应能力的Swing组件。但这种方法的一个缺
点,也是必要的代价是,模型数据不得不重复。另一个问题是,两个模型并非总是同步的,而且它们之间不得不用某种方法来
互相协调。
在展开时更新:动态浏览在展开时更新:动态浏览
模型间的一种协调方法是仅在需要数据时更新本地模型,而非在此之前。这种技术在远程模型很慢或很大时是有用的,但这种
技术要求模型基本上是静态的。DynamicTree用这种方法来浏览一个缓慢的静态树模型。
DynamicTree开始时是一个未展开的根节点,同时有一个展开监听器(expansion listener)等待用户输入来展开节点。当节点
展开后,展开监听器启动一个SwingWorker线程。这个worker的construct()方法访问远程模型并返回新的子节点。然后worker
的finished()方法会在事件派发线程中执行,将子节点添加到本地模型。
为简单起见,在同一时刻仅允许一个worker运行。如果有任何节点被折叠,当前活动的任何worker将被中断。(程序并不检查
折叠的节点是否是worker正在展开的节点的祖先。)
执行顺序执行顺序
图2表示了节点展开的过程。执行过程在图左边的事件派发线程中开始和结束。SwingWorker执行过程在图右边的worker线程中
开始。实线箭头是方法调用,虚线箭头是返回,半箭头则是异步请求。
图2 DynamicTree执行顺序图
本节的余下部分将讨论类结构和实现。你可以也跳过下面的远程模型演示程序。后面的“下载”一节解释了如何下载和运行该演
示程序。
实现实现
图3是一个概略的类结构图。
图3 DynamicTree各类
本地模型是一个包含DefaultMutableTreeNode节点的DefaultTreeModel。节点必须是可变的,以便能够动态地添加子节点。可
变节点的userObject域可以用来指向远程模型。
TreeNodeFactory
远程模型实现了TreeNodeFactory接口:
public interface TreeNodeFactory {
DefaultMutableTreeNode[] createChildren(Object userObject)
throws Exception;
}
createChildren()在worker线程中被调用。类似于大多数异步和远程方法,它会抛出一个异常(一般是一个RemoteException或
InterruptedException)。userObject参数是最近展开的节点指回远程模型的一个链接。一次返回一个包括所有子节点的数组比
单独返回每个子节点更高效,还可以避免面对部分失败的情况。
在初始化时,每个子节点都要被设置allowsChildren属性和一个指回远程模型的链接。(如果远程节点是叶子节点,则
allowsChildren属性设为false;否则allowsChildren被设为true以表明该节点可被展开。)
DefaultTreeNodeFactory是一个Adapter(请参考GOF的《Design Patterns》)。它将任意TreeModel配接成TreeNodeFactory
接口。演示程序中用的是缺省树模型。在main方法中的一些注释掉的代码演示了如何安装一个FileSystemNodeFactory。
SlowTreeNodeFactory是演示用的一个包装类;它在运行中插入随机的延迟。
未来的工作未来的工作
我已经努力使DynamicTree保持简单。节点中除了节点的名字别无其他内容。在节点中需要填充内容的情况下,如果能异步地
加载内容会好一些,比如你可能用一个树选择监听器(tree selection listener)来初始化加载过程。
下一节的远程表演示程序会更实用一些。
-------------------------------------------------------------------------------
远程表远程表
假设你有一个带TableModel的JTable管理着一个远程设备,但接口在设备繁忙时慢如龟爬,你该怎么办?
下面的远程表演示程序使用后台线程和异步的回调操作(asynchronous callbacks)来显示或修改一个远程表模型。
图4是一个远程表编辑器正在向服务器发送新的值。未处理的单元格在更新完成前会保持黄色。
图4
RemoteTable bean
远程表演示程序用RMI实现,它由一个服务器和两个客户端(一个编辑器和一个查看器)组成。查看器实际上只是一个禁止了
编辑功能的编辑器。
客户端使用一个RemoteTable组件bean,RemoteTable是设计成于远程表模型协作的JTable的子类。图4所示的编辑器由一个
RemoteTable组件、一个状态标签、一个简单的活动计量器(右下角)和一些用于定位服务器的代码组成。
得到通知时更新得到通知时更新
DynamicTree仅在需要数据时更新它的本地模型,与此不同的是,RemoteTable组件在一开始就获取所有的数据,然后监听此
后的变化。基于通知(notification-based)的技术可以和动态模型一起工作,且在模型比较小时工作的很好。
对单元格的修改驱动通知。当用户完成对单元格的编辑,RemoteTable把编辑过的单元格标记为未处理的(黄色突出显示)并
且安排一项SwingWorker任务。该woker的construct()方法会把新的值发送到远程模型。
当远程模型接收到新的值,它把变化通知给监听器。Worker的finished()方法的唯一功能是确认任务已完成;在来自远程模型的
通知接受并处理完后,黄色的未处理单元格变回普通单元格。
任务队列任务队列
RemoteTable用一个QueuedExecutor调度它的SwingWorker任务,QueuedExecutor在单个线程中顺序执行所有的任务。
(QueuedExecutor是Doug Lea的util.concurrent包的一部分,请参见后面的“参考资料”部分。)远程模型用RMI回调操作通知
它的监听器。
为了支持可视的反馈,RemoteTable发送Task事件给注册的Task监听器。在任务进入调度时,监听器的taskStarted()被调
用,taskEnded()在任务完成时被调用。客户端演示程序使用这些事件来启动或停止一个小动画并更新状态来。
剩余13页未读,继续阅读
资源评论
weixin_38723516
- 粉丝: 4
- 资源: 982
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
最新资源
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功