原文地址: http://twaver.servasoft.com/?p=562
继上一篇之后应该以后可以少解释为什么要考虑线程安全的了,这篇的重点是如何保证GUI线程安全。
电信网管里最常见的场景莫过于后来来了个告警需要更新界面网元,很多TWaver客户得到后台来的告警信息后很自然的去调用DataBox里Element的AlarmState,或者通过Alarm对象驱动AlarmModel了,这时问题就来了,不管你用的JMS,COBOL,MQ或者是自己起的Socket连接给你的message的thread绝对不是EDT的线程中,所以如果你直接在得到消息后更新UIModel或者UI就是违背了GUI的线程安全原则。
这种情况下你唯一能做的就是将你要做的任务注册到EDT的事件派发队列里面,如果用Swing可以调用SwingUtilities.invokeAndWait或invokeLater,用SWT可以调用Display.asyncExec或syncExec,用Silverlight和WPF可以调用Dispatcher.BeginInvoke,这样通过注册Runnable或者Action之类的任务,等待着EDT在它有空处理你的时候就会调用你的注册的Runnable或Action执行动作了,这时候在里面就是这个唯一的UI Thread在运行了,这里面你大可放心的去操作UI或绑定UI的Model,唯一需要注意的是UI Thread全局就一个在工作,当你在执行时用户界面是不会得到任何响应的,因此你必须快速处理别站着茅坑***,假设你处理了半分钟,那对用户来说他会告诉你死机了半分钟。(有人留意到我怎么没提到Flex和JavaScript的调用函数,这两个UI平台比较特殊,下篇我再细讲)。
TWaver的Demo的有很多地方都有模拟实时更新的应用,大家可以参考一下
除了调用上面提到的一些比较常规的invoke方式外你还可以考虑用Timer,SWT里面你可以调用Display.timerExec,Swing里面javax.swing.Timer,注意我这里指的不是java.util.Timer,用util的Timer那基本我们前面说的做的都白费了,javax.swing包下的那个Timer才能保证回调时的Thread是EDT,同样.NET下有起码四五个叫Timer的兄弟,System.Windows.Threading.DispatcherTimer这个我比较常用,我估计笨到能去调用System.Web.UI.Timer的人估计没兴趣在看我这枯草的全是代码的文章吧,如果你想深入了解微软问什么搞了这么多个Timer来折磨程序员的话你可以读读这篇和这篇,这里不得的赞叹微软一下,大家都这家伙够啥都能搞成恐龙级,不过这家伙养的那只恐龙都有浩如烟海的详尽文档将每个细胞描述的滴水不漏,而且几乎不见文档语法带个错字的,这点很少有公司能做的足够好的,即使是google更不用说adobe了,不过文档做不到完善也无妨,只要产品质量过硬也无伤大雅,所以大家要是看到我文章的错别字还请海涵,kao,扯远了回到正题吧。
刚才上面还提到一个注意点就是在EDT里面不要执行太长时间否则用户体验很差,这点往往就是大部分不熟悉传统GUI开发者的错误偏见:CS很重很慢BS很轻量是趋势。产生这种偏见的根源我觉得是这样的:不管开发desktop还是web甚至是逐渐流行的mobile和tablet应用程序,要达到良好的用户体验都需要深入了解你所使用的GUI平台技术,但在目前这种浮躁的、项目型的、短期利益驱动的时代,你很难想象可以为一个项目中标后立刻在短期内扩展几十上百号人,或者租借大批今天做你们公司项目明天做其他公司项目的人员,而且几乎都是既懂得AIX下Oracle的tuning,又能充当美工ps两下,甚至对项目管理工具游刃有余的可以临时充当PM的万精油类型。
这些年我支持了可以说上百家的客户的确有见不仅可以“万”而且可以“精”者,但这毕竟是少数大部分都是一知半解的就开始冲锋上阵了,因此固然非常容易很多没有经验的程序员在EDT里面做一大堆工作,甚至是通讯查询数据库的工作都搞在里面了,如果能不慢那才是奇迹了,而Web的程序员里面没经验的比例其实和desktop类型的是基本一样的(争辩这个好比争辩男人聪明还是女人聪明,其实据统计学看绝顶聪明的、一般的已经弱智的比例基本是一样的),只不过Web的应用大部分获取数据在后台直接进行了,推到前台的基本就是HTML的呈现UI信息了,所以是慢在后台了用户看不见而已,用户打开一个页面很慢他是会说服务器很慢啊,他绝对不会说浏览器的HTML渲染解析引擎好慢。俺以前也经历过个庞大的项目,以前用PB做客户端,忘了是SqlServer97还是2000,跑在多年前很普通的Windows服务器上,就这么样配置架构的系统很好的能快速响应的服务于一个城市多年,后来我们这些家伙就来了,换成了HP小机(一款新出的机型,转个JDK都得到他们官方网站专门定做的JDK才能装的上,后来遇到不知道多少的咨询尝试我们才活了下来),竟然采用了Oracle的J2EE容器(六七年前大家只知道WebLogic、WebSphere和JBoss,一个三四十号人的J2EE开发团队没人见过Oracle的J2EE容器是个什么样的家伙,后来果不其然这玩意儿没少折腾我们),说实话这个系统如果按当初老系统的服务器配置根本就跑不了任何应用,完全靠的是惊人的后台N多CPU,-Xmx$$G,加上不可思议的IO能力才解决了问题,可以说是靠钱堆出了勉强可以的用户体验。
上面这个案例我只想说明不管什么应用程序要有好的应用体验一定要将数据的获取和UI的呈现逻辑分离,否则Web应用可以通过加大后台服务器配置哪怕你的SQL写的效率低点也有补救的可能(当然优化代码和SQL才是根本这个我就不争辩了),但desktop程序如果在UI Thread搞入一大堆密集预算或者长期等待的逻辑操作的话,那基本无药可救了,哪怕你让客户配置上100核的CPU也只有一个Thread在工作。
讲了这么多大道理,让我们上代码吧,我这里强烈推荐大家阅读以下TWaver的FileTreeDemo,以下两个抓图分别是TWaver Java和TWaver .NET例子的抓图
public void loadChildren(final FileElement element) {
final String oldIconURL = element.getIconURL();
element.setIcon(loadingIcon);
Thread t = new Thread(new Runnable(){
public void run() {
// fileSystemView.getFiles may cost a lot of time,
// so we create all element in NOT swing thead.
File file = element.getFile();
File[] files = fileSystemView.getFiles(file, true);
final List children = new ArrayList();
if (files != null && files.length > 0) {
for (int i = 0; i < files.length; ++i) {
children.add(createElement(files[i]));
}
}
// when you want to add element to the box that
// already connected with swing component like tree,
// network, table, sheet, etc. you should do this
// job in swing thread.
SwingUtilities.invokeLater(new Runnable(){
public void run() {
box.addElements(children, element);
element.setLoaded(true);
element.setIcon(oldIconURL);
decreaseCounter();
}
});
}
});
increaseCounter();
t.start();
}
以上代码已经说明了我想说的重点,也就是当你expand目录节点时TWaver才需要你动态加载子目录数据,expend时回调的loadChildren事件就是在EDT中,而读取磁盘文件是耗时的操作,如果你直接在EDT里面查询子目录并且创建对于的element信息,肯定界面需要堵塞住知道磁盘子目录和文件读完界面才有反应,TWaver Demo的实现起了个线程去做获取数据的工作,这里注意到element其实是在普通线程创建的,这里没有问题因为其还未添加到box,还不会影响到view上,而box已经和tree绑定了,因此对box的操作必然会影响tree的更新,因此数据获并且创建成element对象之后才通过SwingUtilities.invokeLater将element添加给box,这样你才有肯呢个看到右边不断滚动的tracing信息。
面包啃完了,浓茶被我冲泡得像白开水了,先睡了明天继续
分享到:
相关推荐
《深入浅出Java》这本书以其独特的讲解方式,旨在让学习者轻松掌握复杂的Java编程语言。"深入浅出"这一理念,意味着作者通过直观、生动的示例和丰富的图解,帮助读者逐步理解Java的核心概念和技术。 Java是一种广泛...
### 深入浅出Java多线程程序设计 在当今高性能计算环境下,多线程技术已成为提升软件性能的关键手段之一。《深入浅出Java多线程程序设计》旨在为读者提供一个系统全面地理解Java多线程机制的平台。通过本篇文章,...
3. **全面覆盖**:《深入浅出MFC》不仅介绍了MFC的基本概念,还涵盖了高级主题,如多线程编程、网络通信等。 4. **版本兼容性**:尽管书中使用的开发环境是Visual C++ 5.0和MFC 4.2,但由于MFC的核心架构变化不大,...
《MFC深入浅出第二版源代码》是一个与知名编程图书配套的源代码资源,它为读者提供了实际操作和理解MFC(Microsoft Foundation Classes)框架的机会。MFC是微软为Windows应用程序开发提供的一种C++库,它封装了...
4. **深入浅出MFC简体中文版**:Microsoft Foundation Classes (MFC) 是一个C++库,用于构建Windows应用程序。本书以易于理解的方式介绍了MFC的架构和用法,包括文档/视图架构、对话框、控件、数据库访问等,帮助...
《深入浅出MFC》是著名C++专家侯捷撰写的一本关于Microsoft Foundation Classes (MFC) 的经典著作。MFC是由微软开发的一个C++类库,它为Windows应用程序开发提供了一种抽象和封装,使得开发者可以更方便地利用...
在图形用户界面设计方面,《深入浅出MFC(第二版)简体版》详细介绍了MFC的GUI编程,包括菜单、工具栏、状态栏的创建与管理,以及自定义控件的实现。读者将学会如何利用MFC提供的类和方法来创建美观、功能丰富的用户...
它提供了标准库,包括了各种功能,比如图形用户界面GUI、网络编程、数据库连接等。这使得程序员在开发各种应用程序时可以方便地调用这些类库,提高开发效率。 另外,java还支持泛型编程。泛型可以让你编写更通用的...
《深入浅出MFC程序设计》是一本专为学习Microsoft Foundation Classes (MFC) 设计的书籍,旨在帮助读者深入理解和熟练运用MFC进行Windows应用程序开发。MFC是微软提供的一套C++类库,它封装了Windows API,使得...
《深入浅出MFC》第二版,由侯捷(侯俊杰)撰写,是一本针对Microsoft Foundation Classes(MFC)框架的深入解析书籍。MFC是微软开发的一个C++类库,主要用于简化Windows应用程序的开发过程。这本书籍的第二版原本于...
《深入浅出Java语言程序设计》是一本专为Java初学者和进阶者精心编写的教程,旨在帮助读者全面理解并掌握Java编程的核心概念和技术。本书涵盖了从基础语法到高级特性的广泛内容,旨在使读者能够熟练运用Java进行软件...
本资源“深入浅出JAVASwing程序设计”旨在帮助开发者掌握Swing的基本概念、组件用法以及高级特性,从而能创建功能强大、交互性强的Java应用。 Swing在Java AWT(Abstract Window Toolkit)的基础上构建,提供了更轻...
本资源"深入浅出JAVA Swing程序设计 书+代码"旨在帮助开发者深入理解Swing,并通过实例代码进行实践,提升Java桌面应用的开发能力。 Swing提供了一套完全由Java实现的组件,这些组件不仅功能强大,而且在跨平台兼容...
《深入浅出:使用Python编程》是一本专为Python初学者设计的教程,旨在帮助读者快速掌握这门强大且易学的编程语言。Python作为现代软件开发中的主流语言,广泛应用于数据分析、机器学习、Web开发等多个领域。这本书...
本资源"深入浅出Java Swing程序设计_11394260.rar"显然是一个关于Java Swing编程的详细教程,涵盖了Swing的基本概念、组件使用、事件处理以及高级特性等。 Swing提供了丰富的组件集,包括按钮、文本框、标签、菜单...