`

Swing多线程编程

    博客分类:
  • java
阅读更多

本文论述了怎样开发多线程的Swing程序,从而提高Swing程序的响应速度和性能。
    近期,我将推出一系列研究Swing程序的文章,这也算是为了向Swing这个优秀的GUI库的设计者致敬吧!
Swing这种优秀的GUI库一直不能占领桌面市场,实在令人费解,今天,我就用我的努力,为java在桌面市场的成功尽我微薄之力吧!


Swing的单线程开发机制
多线程开发,显然要比单线程开发有趣、高效、美妙得多。特别是在Java这种天生支持多线程的语言中,更是如此。可是,Java最重要的组成部分Swing确是单线程的!
并非只有Swing是单线程的,大多数GUI库都是单线程的。因为,在GUI的事件处理中,事件和处理事件的底层资源是如此的复杂,以至于使用多线程开发,很难避免死锁和资源竞争问题的发生。而且,如果锁定太多系统资源,对GUI的系统性能将会造成消极影响。
因此,Swing被开发成了一个基于事件队列的单线程编程模型。GUI上的事件,一个个依次在“事件派发线程”上执行,不会发生事件对资源的争夺。
Java.awt.EventQueue类,就执行这个功能。
EventQueue 是一个与平台无关的类,它将来自于基础同位体类和受信任的应用程序类的事件列入队列。
它封装了异步事件指派机制,该机制从队列中提取事件,然后通过对此 EventQueue 调用 dispatchEvent(AWTEvent) 方法来指派这些事件(事件作为参数被指派)。该机制的特殊行为是与实现有关的。指派实际排入到该队列中的事件(注意,正在发送到 EventQueue 中的事件可以被合并)的惟一要求是:
按顺序。
也就是说,不允许同时从该队列中指派多个事件。
指派顺序与它们排队的顺序相同。
也就是说,如果 AWTEvent A 比 AWTEvent B 先排入到 EventQueue 中,那么事件 B 不能在事件 A 之前被指派。
一些浏览器将不同基本代码中的 applet 分成独立的上下文,并在这些上下文之间建立一道道墙。在这样的场景中,每个上下文将会有一个 EventQueue。其他浏览器将所有的 applet 放入到同一个上下文中,这意味着所有 applet 只有一个全局 EventQueue。该行为是与实现有关的。有关更多信息,请参照浏览器的文档。
所有Swing/AWT事件的处理方法,都被放到唯一的“事件派发线程”中执行。
一般,我们使用EventQueue类的2个方法,将事件处理方法放到“事件派发线程”中执行。
invokeLater
public static void invokeLater(Runnable runnable)导致 runnable 的 run 方法在 EventQueue 的指派线程上被调用。在所有挂起事件被处理后才发生。
参数:
runnable - Runnable,其 run 方法应该在 EventQueue 上同步执行
从以下版本开始:
1.2
另请参见:
invokeAndWait(java.lang.Runnable)

--------------------------------------------------------------------------------

invokeAndWait
public static void invokeAndWait(Runnable runnable)                          throws InterruptedException,                                 InvocationTargetException导致 runnable 的 run 方法在 EventQueue 的指派线程上被调用。在所有挂起事件被处理后才发生。在这发生之前调用被阻塞。如果从事件指派线程进行调用,则该方法将抛出 Error。
参数:
runnable - Runnable,其 run 方法应该在 EventQueue 上同步执行
抛出:
InterruptedException - 如果另一个线程已经中断了该线程
InvocationTargetException - 如果运行 runnable 时抛出一个 throwable
从以下版本开始:
1.2
另请参见:
invokeLater(java.lang.Runnable)

--------------------------------------------------------------------------------

设计Swing的UI组件的执行,一般都需要运行在“事件派发线程”上。


Swing单线程开发引起的问题
Java是一种多线程编程语言。多线程给程序带来了并发的好处。Swing单线程开发的一个问题是,如果在“事件派发线程”上执行的运算太多,那么GUI界面就会停住,系统响应和运算就会非常缓慢。
既然,“事件派发线程”是为了处理GUI事件而设的,那么,我们只应该把GUI事件处理相关的代码,放在“事件派发线程”中执行。其他与界面无关的代码,应该放在Java其他的线程中执行。
这样,我们在Swing的事件处理中,仍然使用Swing的单线程编程模型,而其他业务操作均使用多线程编程模型,这就可以大大提高Swing程序的响应和运行速度,充分运用Java多线程编程的优势。

Swing程序的线程
Swing应用程序的线程,分为两种,一种是“事件派发线程”,实际上只有唯一的一条线程;另一种是一般的Java线程,可以有无数条线程。
与系统事件处理相关的代码,需要运行在“事件派发线程”中。一般就是Swing的UI组件。Swing组件,由于包含了SwingUI组件,所以常常也需要运行在“事件派发线程”中。
与业务相关的代码,特别是大计算量,或者涉及到IO,网络,等待资源等耗时的操作,需要放置到一个独立的Java线程中,实现并行运算,提高性能。

Swing程序线程应用示例
下面,我以一个一般的Swing程序为例,具体说明Swing多线程编程应该怎样进行。
1,JFrame子类:
public class DiagramDesignerJFrame extends javax.swing.JFrame {…}
这是一个JFrame的子类,是一个顶级窗口。顶级窗口,就是一个从操作系统中拿到的窗口。Java可以在这个窗口中使用从操作系统得到的画笔,绘制出Swing需要的GUI。

2,main方法:

    /**
    
*@paramargs
     *            thecommandlinearguments
     */
    publicstaticvoid main(String args[]) {
        /**
         *在一般线程中,执行SPring容器的初始化
         */
        try {
            SpringUtil.getCtx();
        } catch (BeansException e) {
            /*
            *
            */
            e.printStackTrace();
        } catch (DocumentException e) {
            /*
            *
            */
            e.printStackTrace();
        }
        java.awt.EventQueue.invokeLater(new Runnable() {
            publicvoid run() {
                new DiagramDesignerJFrame().setVisible(true);
            }
        });
    }

首先,我们在一般Java线程中,执行Spring容器的初始化。这是非常大量的计算,而且与操作系统事件根本没有关系。
然后,我们在“事件派发线程”中异步执行对JFrame的子类的实例化和可视化。
new DiagramDesignerJFrame()这个实例化操作,是在“事件派发线程”中执行的;
setVisible(true)也是在“事件派发线程”中执行的。


控制器中多线程的运用
Swing是MVC模式设计的典范。其控制器,就是事件监听器,一般实现为内部类。Swing各个组件都可以注册非常多的事件监听器,也就是“控制器”。
Swing的UI组件,是其界面View。各个Swing组件的Model是其模型。
一般,用户在Swing的UI组件上执行操作,激发事件,然后由控制器进行处理,修改Swing组件的Model。Model又激发Java事件(而非操作系统事件),使UI根据新的Model值重绘。
我们在“控制器”中会调用业务代码,这些代码可能会很耗时。调用结束以后,常常又会调用Swing组件的方法,更新Swing应用程序的外观。
因此,我们应该在Swing的控制器中,把调用业务方法的代码,交给一个新建的一般Java线程去执行。执行完毕之后,再在“事件派发线程”中执行Swing组件更新代码。
    下面是执行“另存为”功能的控制器。它首先保存Swing组件中的数据,然后打开文件选择其对话框,让用户选择要保存到哪个文件中。
/**
    
*@returnsaveAsActionListener
     */
    public ActionListener getSaveAsActionListener() {
        if (this.saveAsActionListener == null) {
            this.saveAsActionListener = new ActionListener() {
                /**
                 *响应点击另存为按钮的事件的方法
                 */
                publicvoid actionPerformed(ActionEvent e) {
                    final SwingWorker worker = new SwingWorker() {

                        @Override
                        public Object construct() {
                            /*
                            *
                            */

                        try {
                            getJEditorPane1().fireControllerChangeListener();
                             return DiagramDesignerJFrame.serviceFinished;
                        } catch (DocumentException e1) {
                            /*
                             *
                             */
                            e1.printStackTrace();
                            JOptionPane.showMessageDialog(
                                    DiagramDesignerJFrame.this, "您的输入不符合xml格式要求!"
                                            + e1.getMessage());
                        } catch (Exception e1) {
                            /*
                             *
                             */
                            e1.printStackTrace();
                        }
                            returnnull;
                        }
                        /**
                         *执行完构造器后,在GUI上异步执行它。
                         */
                         publicvoid finished() {
                             saveAction();
                            }
                       
                    };
                    worker.start();
                   
               

                   

                }

            };

        }

        returnsaveAsActionListener;
    }

SwingWorker这个Swing多线程开发的助手类
上面的例子中用到了SwingWorker这个Swing多线程开发的助手类。在JDK6中,这个类已经作为Swing的一部分。这里,我使用的是JDK5,因此,我是使用了之前SUN创建的SwingWorker类。
其中,public Object construct() {…}
这个方法中的代码,运行在一个新建的一般Java线程中。我们把耗时的业务方法放在这个方法中执行。
publicvoid finished() {…}
这个方法中的代码,运行在“事件派发线程”中,是立即返回的。saveAction()显示了一个文件选择其对话框,应该在这里执行!
只有当construct()执行完毕后,才会执行finished()方法。


结语
    上面就是关于Swing多线程开发的一些论述。注意到Swing单线程事件队列开发模型这个事实,你就能够合理的把代码分配到一般Java线程和Swing事件派发线程中,提高Swing应用的性能。

分享到:
评论
1 楼 lfrick 2011-01-17  
感谢指点,近期正准备深入研究一下swing。

相关推荐

    java Swing 多线程下载器

    总的来说,Java Swing多线程下载器结合了Java的GUI编程、多线程技术以及文件操作,为用户提供了一个功能强大的下载工具。开发这样一个程序需要深入理解Java的并发编程和Swing组件的使用,同时也需要对网络通信和文件...

    Java Swing多线程死锁问题解析

    Java Swing多线程死锁问题解析 Java Swing多线程死锁问题解析是...在实际开发中,我们需要遵循Java Swing多线程编程的基本原则,正确地使用多线程技术,避免死锁和其他问题的出现,使我们的程序更加稳定、高速和高效。

    基于swing的多线程聊天室

    【基于Swing的多线程聊天室】是一个...总结,基于Swing的多线程聊天室是一个综合运用了GUI设计、多线程、网络编程以及数据处理等技术的项目。通过这种方式,可以创建出一个高效、响应迅速并且用户体验良好的聊天应用。

    JAVASWING多线程产生随机球

    Java Swing 是Java GUI(图形用户界面)...通过以上知识点的综合运用,"JAVASWING多线程产生随机球"项目实现了交互式的图形展示,展示了Java Swing在GUI编程中的灵活性和多线程技术在实现复杂动画效果时的重要作用。

    基于swing多线程的赛马游戏

    总的来说,“基于Swing多线程的赛马游戏”是一个综合性的项目,它涵盖了Java Swing GUI设计、多线程编程、并发控制、数据结构、用户交互等多个方面。这个案例对于初学者来说是一个绝佳的学习资源,通过实际操作可以...

    JAVA编写的多线程小弹球测试

    在Java编程领域,多线程是一项重要的技术,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在“JAVA编写的多线程小弹球测试”项目中,开发者利用Java语言创建了一个生动有趣的多线程应用,即一个模拟...

    Java Swing制作多行滚动歌词显示控件.doc

    Java Swing 制作多行滚动歌词显示控件 ...Java Swing 制作多行滚动歌词显示控件需要使用到多种技术和组件,包括领域模型、Java Swing 组件、布局管理、事件处理、图形用户界面设计、多线程编程和调试技术等。

    Java多线程编程

    ### Java多线程编程知识点详解 #### 一、线程基础概述 - **定义与特点:** - **线程**是一种比进程更细粒度的执行单元,它允许在一个进程中并发执行多个任务。 - **轻量级进程**:线程有时被称为轻量级进程,...

    JAVA 开发 Swing与多线程

    在Java开发中,Swing库是用来构建图形用户界面(GUI)的工具包,而多线程则是提升程序并发性能和响应能力的关键技术。Swing虽然是Java语言的一部分,但它设计为单线程模型,主要是为了简化GUI编程并避免复杂的同步...

    基于java swing的多线程电梯调度模拟

    总的来说,这个项目涉及到Java多线程编程、GUI设计、对象间的通信以及线程同步等多个核心概念,是学习和实践Java并发编程的好例子。通过理解和分析这个项目,开发者不仅可以深入理解Java的并发机制,还能掌握如何在...

    Javaswing多线程.zip

    在这个“Javaswing多线程.zip”项目中,开发者创建了一个包含四个标签(JLabels)的窗口,这些标签会按照一定的时间间隔轮流显示或隐藏,这通常是为了创建某种动画效果或者信息滚动展示。在Swing中,我们通常使用`...

    swing,线程和网络编程教学示例

    线程是程序执行的独立路径,Java支持多线程编程,这使得程序可以在同一时间执行多个任务。 1. **Thread类与Runnable接口:** 创建线程有两种方式,一是继承Thread类,二是实现Runnable接口。后者更灵活,因为它可以...

    swing界面socket多线程聊天室

    综上所述,这个“swing界面socket多线程聊天室”项目涵盖了Java GUI设计、网络编程、多线程技术、文件传输以及用户管理等多个关键领域,是学习和实践这些技能的好例子。通过分析和实现这样的项目,开发者可以深入...

    JAVA SWING 多线程扫描局域网IP及端口 v2 源码

    Java Swing 是Java GUI(图形用户界面)库的一部分,它提供了丰富的组件...这个源码项目为学习Java Swing、多线程编程、网络扫描等技术提供了一个实用的示例,对于想要深入这些领域的开发者来说,具有很高的参考价值。

    java 多线程编程

    Java多线程编程是Java开发中的重要组成部分,它允许程序同时执行多个任务,极大地提高了程序的效率和响应性。在Java中,实现多线程有两种主要方式:通过继承`Thread`类或者实现`Runnable`接口。 1. **继承Thread类*...

    java多线程+Socket+Swing做的局域网聊天程序

    【标题】"java多线程+Socket+Swing做的局域网聊天程序"涉及的核心知识点主要涵盖Java编程、多线程、网络通信以及图形用户界面设计。以下将详细阐述这些关键概念及其在实现局域网聊天程序中的应用。 **1. Java编程**...

    JavaSwing多人猜拳

    尽管缺少源代码,我们可以推断出这个JavaSwing应用涉及到的技术和概念,包括图形用户界面设计、事件处理、多线程、网络编程(如果适用)、游戏逻辑实现以及可能的数据持久化。对于想要学习JavaSwing或者想了解如何...

    java多线程编程

    ### Java多线程编程知识点详解 #### 一、线程基础与概念 **1. 进程与线程** 线程是比进程更轻量级的执行单元,它允许在一个进程中并发执行多个任务。进程是资源分配和调度的基本单位,而线程则是CPU调度和分派的...

    多线程抢红包带SwingUI

    本项目“多线程抢红包带SwingUI”就是一个很好的实践示例,它结合了Java的Swing库来创建图形用户界面(GUI),使用户可以直观地体验到多线程编程的效果。 首先,我们要理解什么是多线程。在单线程程序中,所有操作...

    JAVA+多线程+swing和awt技术+ 飞机大战+学习Java者

    标题中的“JAVA+多线程+swing和awt技术+ 飞机大战+学习Java者”揭示了这个压缩包包含的内容是关于Java编程的,特别是涉及到多线程和图形用户界面(GUI)开发,使用了Java的Swing和AWT库来实现一个“飞机大战”的游戏...

Global site tag (gtag.js) - Google Analytics