`
vearn
  • 浏览: 58854 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用SwingWorker异步加载JTree

阅读更多

 

SwingWorker是Java SE 6.0新加入的一个工具包,利用它可以使长时间运行并更新用户界面的任务大大简化。本文以一个异步加载JTree的demo演示了SwingWorker的基本功能。

 

环境准备

 

软件或资源 要求的版本
Java Development Kit (JDK) 6.0(5.0需要自行加入swingworker到classpath)
NetBeans IDE 6.5
Java DB 10.4.1.3 - (648739)

 

运行demo

  1. 从附件中下载asynch_load_tree.zip到本地并解压。
  2. NetBeans主菜单依次选择“文件”——“打开项目”。
  3. 在弹出的“打开项目”对话框中选择刚才解压之后的asynch_load_tree目录,点击“打开项目”按钮。
  4. 在“文件”视图中找到asynch_load_tree项目下的init_schema_and_data.sql,按照下图步骤操作。

     
  5. 在“项目”视图中找到asynch_load_tree项目,在上下文菜单中选择“运行”项。
  6. 按照下图操作,看一下在EDT 中执行耗时阻塞任务的严重后果。

     
     

EDT是啥米呀

 

在Java中,键盘输入、鼠标点击或者应用程序本身产生的请求会被封装成一个事件,放进一个事件队列中,java.awt.EventQueue对象负责从这个队列中取出事件并派发它们。而EventQueue的派发有一个单独的线程管理,这个线程叫做事件派发线程(Event Dispatch Thread),也就是EDT。此外,Swing的绘制请求也是通过EDT来派发的。

 

根据以上这两个事实,我们就可以解释刚才demo中发生的事情。当checkbox被选中之后,再双击根结点,触发了以下的程序:

 

public void treeExpanded(TreeExpansionEvent event) {
    long handleTime = readHugeData();
    label.setText("处理时间为" + handleTime);
}

事实上,在demo中是用Thread.sleep()方法来模拟readHugeData这个从数据库中读取大量记录这个阻塞方法。那么在这种情况下,EDT在等待数据库的返回期间是不能接收任何事件(比如键盘输入),也不能处理任何组件的绘制。

 

解决的方法是什么呢?很容易想到,把耗时的方法从EDT中剥离出来,放到单独的工作线程中执行。例如下面这样:

 

public void treeExpanded(TreeExpansionEvent event) {
    new Thread(new Runnable() {
        public void run() {
            long handleTime = readHugeData();
            label.setText("处理时间为" + handleTime);
        }
    }).start();
}

很遗憾,这段代码违反了Swing的单线程原则:即没有在EDT上,而是在工作线程里修改这个label的状态。根据SUN的说法,在测试时可能没问题,但死锁可能随时出现,而且多半发生在给老板演示的时候:>

 

在SwingWorker出现之前的解决方法是javax.swing.SwingUtilities类的invokeLater方法。在上面的代码片断中,只需将更新label状态的工作封装成一个Runnable的示例,然后作为参数传递给invokeLater()就好了:

 

public void treeExpanded(TreeExpansionEvent event) {
    new Thread(new Runnable() {
        public void run() {
            final long handleTime = readHugeData();
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {       
                    label.setText("处理时间为" + handleTime);
                }
            });
        }
    }).start();
}

这样就可以保证demo可以平稳和正确地运行了,但是,要创建好多匿名的Runnable,导致代码难于阅读和维护。为了简化与EDT的交互,SwingWorker登场了。


SwingWorker入门

 

这个demo中涉及的只是SwingWorker最基础的东东,所以不必担心。看看如何使用把:

 

public void treeExpanded(TreeExpansionEvent event) {
    new SwingWorker<Long, Void>() {
        @Override
        protected Long doInBackground() {
	     return readHugeData();
        }
        @Override
        protected void done() {
            label.setText("处理时间为" + get());
        }
    }.execute();
}

 

我们把耗时阻塞任务放到doInBackground()方法中,更新组件状态的任务放到done()方法中。当任务完成后,SwingWorder自动调用EDT中的done()方法。此外在done()方法中,可以调用get()方法获取doInBackground()方法的返回值,在demo中这个返回值是任务处理时长。好了,SwingWorker就讲到这里了。什么,那个new SwingWorker<Long, Void>()中第二个泛型类型Void是啥意思?请参考Improve Application Performance With SwingWorker in Java SE 6 这篇牛文。

 

demo的其他细节

 

关于如何自定义TreeNode类、怎样初始化JTree、异步读取所有子结点等问题。还是请看代码把,人家很用心写了注释的说。。。

 

  • 大小: 47.3 KB
  • 大小: 23.4 KB
20
0
分享到:
评论
10 楼 yedaya 2013-03-31  
楼主,您好,
请问,如果在doInBackground方法中要不断更新画面该如何和ETD交互呢?
9 楼 lecroy 2012-09-28  
谢谢!
8 楼 DISHIKUN2008 2012-05-30  
非常好!谢了啊!
7 楼 java1997 2012-05-16  
人家很用心写了注释的说。。。

正在研究这个问题,太感谢了!
6 楼 itlangqun 2012-05-02  
不错,今天算是明白了
5 楼 ybyonline 2010-12-24  
正好碰到这个问题,swingwoker用到派发线程,能处理好多问题!
4 楼 steeven 2009-04-29  
swingworker终于扶正了.....

面试的时候几乎没人知道这玩意, 连swing多线程问题都没几个人知道. 弄得我都不敢问了
3 楼 rosa_[Lamina] 2009-03-12  
不错啊!Thanks!
2 楼 javaDevil 2009-03-08  
         不错。
1 楼 gml520 2009-03-07  
Thank you!

相关推荐

    Swing线程的最后讨论 -- 利用异步模型

    通过这种方式,开发者可以异步加载数据,从而避免阻塞用户界面,提高应用的用户体验。 文章最后还提到了下载资源和结论,总结了如何在实际项目中应用这些策略,并提供了进一步学习的参考资料。 总的来说,本文深入...

    JTree2.0 目录树demo源码

    - **数据加载**:如果Demo涉及到动态加载,可能有异步请求服务器数据的部分,使用`SwingWorker`确保在事件调度线程中更新UI。 5. **JavaScript与ECMAScript** - 虽然`JTree`是Java组件,但描述中提到了`...

    树菜单

    此外,可能会讨论如何使用SwingWorker或其他异步机制来避免UI线程阻塞,确保用户界面的流畅性。 总之,JTree是Java Swing中构建树形菜单的强大工具,理解和熟练使用它可以提升应用的用户界面和交互体验。通过深入...

    Java目录树控件

    可以使用SwingWorker或JavaFX的Task来异步处理。 通过以上步骤,我们可以创建一个基本的Java目录树控件,显示和操作文件系统。实际项目中,可能还需要考虑权限控制、搜索功能、拖放操作等高级特性,这需要进一步...

    CSDN树形控件-静态

    如果需要动态加载数据,可能需要结合SwingWorker或线程来异步加载数据,避免阻塞UI。 8. **MzTreeView2**:这个压缩包内的“mztreeview2”可能是一个特定的树形控件实现或示例,可能包含自定义的扩展功能或优化。要...

    Java通信项目之客户端UI实现以及交互

    - 使用异步加载策略,如懒加载,减少初始加载时间。 在实际开发过程中,可能还需要结合设计模式(如MVC、MVVM)来组织代码,使代码结构清晰,易于维护。同时,单元测试和集成测试也是保证项目质量的重要环节。通过...

    swing编写我的电脑窗口

    6. **线程安全**:考虑到GUI的异步性质,可能需要使用SwingWorker来执行耗时操作,如加载大量文件或执行文件操作,以免阻塞事件调度线程。 7. **布局管理**:Swing提供多种布局管理器,如FlowLayout、BorderLayout...

    java经典源代码2

    案例可能涵盖了如何使用SwingWorker实现异步处理。 9. **拖放(DnD)功能**:Java Swing支持拖放操作,使得用户可以通过鼠标拖动数据在组件间转移。学习源代码,你会看到如何启用和处理拖放事件。 10. **图形绘制**...

    java实现的系统目录展示系统

    为了保持界面的响应性,可能会使用Worker Threads(如SwingWorker)来执行耗时的操作,如加载目录结构,这样主线程可以继续处理用户的交互请求。 文件过滤是另一个关键特性,允许用户根据文件类型或名称进行筛选。...

    开发J2EE应用的要领

    - 当监听器检测到用户尝试展开某个节点时,触发`SwingWorker`执行任务以加载远程数据。 #### 结论 本文通过介绍修订版`SwingWorker`及其在处理动态树中的应用,展示了如何克服Swing单线程规则带来的局限性。通过...

    Java swing 权威指南

    11. **SwingWorker**: 这是Swing提供的异步执行模型,用于在后台线程执行耗时任务,防止GUI线程阻塞,保持界面的响应性。 12. **外观(Look and Feel)**: Swing 允许更改应用的外观和感觉,可以使用系统默认的Look...

    java swing

    6. **SwingWorker**:这是Swing提供的一种异步编程机制,用于在后台线程执行耗时操作,避免阻塞用户界面。 7. **自定义外观(LookAndFeel)**:通过LookAndFeel类,开发者可以改变Swing组件的外观,使其与操作系统...

Global site tag (gtag.js) - Google Analytics