Swing多線程編程

來源:互聯網
上載者:User
  

                                                            Swing多線程編程關鍵字:Swing,多線程,GUI,SwingWorker摘要:本文論述了怎樣開發多線程的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應用的效能。  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.