2008-11-11 86 views

回答

10

是的,您可以使用vanilla threads + invokeLater完成SwingWorker的工作。 SwingWorker提供了一種可預測的集成方式來完成後臺線程上的任務並在EDT上報告結果。 SwingWorker另外增加了對中間結果的支持。再次,您可以自己完成所有這些工作,但有時使用集成和可預測的解決方案很容易,特別是在涉及到併發時。

2

的SwingWorker是一種常見的模式的實現(在.net中,我讀有 GuiWorker BackgroundWorker的這個),在那裏你必須做一些工作中的GUI程序,但保持GUI響應。問題在於GUI庫通常不是多線程安全的,所以實現這種工作的通用方式是使用庫的消息循環將消息傳輸到應用程序的事件循環中。

這些類允許您輕鬆更新您的GUI。通常,它們有一個由線程調用的方法,由該類調度並由GUI處理,而線程則繼續其工作。

使用普通線程時,您需要爲此任務編寫自己的事件或其他消息傳遞機制,如果經常需要此功能,這可能會很痛苦。例如,在Java中使用invokeLater,可以將用於更新gui的代碼混合爲用於執行該工作的代碼。 SwingWorker允許你保持獨立。

+0

您還需要使用SwingWorker的偵聽器。所以? – OscarRyz 2008-11-11 19:30:27

+0

我的意思是你需要自己的監聽器(不是已經創建的監聽器接口)來管理你自己的事件。 SwingWorker爲你處理所有這些。例如,您可以覆蓋方法「完成」,這是在工作人員完成時調用的。 – 2008-11-11 19:53:29

1

回答你的問題,你不會錯過任何東西。這個類只是一個方便的工具,用於包裝你描述的功能(啓動另一個線程來完成後臺工作,然後在結果中調用EDT上的最後一個動作)。

3

一個代碼示例:

import org.jdesktop.swingx.util.SwingWorker; // This one is from swingx 
              // another one is built in 
              // since JDK 1.6 AFAIK? 

public class SwingWorkerTest { 

    public static void main(String[] args) { 

    /** 
     * First method 
     */ 
    new Thread() { 

     public void run() { 

     /** Do work that would freeze GUI here */ 

     final Object result = new Object(); 
     java.awt.EventQueue.invokeLater(new Runnable() { 

      public void run() { 
      /** Update GUI here */ 
      } 
     }); 

     } 
    }.start(); 

    /** 
     * Second method 
     */ 
    new SwingWorker< Object , Object >() { 

     protected Object doInBackground() throws Exception { 
     /** Do work that would freeze GUI here */ 

     return null; 
     } 

     protected void done() { 
     try { 
      Object result = get(); 
      /** Update GUI here */ 
     } 
     catch (Exception ex) { 
      ex.printStackTrace(); 
      if (ex instanceof java.lang.InterruptedException) 
      return; 
     } 
     } 
    }.execute(); 
    } 

} 

的選擇總是取決於個人的喜好和使用情況。

第二種方法在重構時具有優勢。當它使用的方法過大時,您可以更輕鬆地將匿名類轉換爲內部類。

我個人的偏好轉向第二個,因爲我們已經建立了一個框架,SwingWorkers可以添加和執行一個接一個......

0

SwingWorker使得簡單的例子,代碼簡潔得多。然而它創造了一個泥球。 GUI和執行邏輯之間的通信都是焊接在一起的。所以,我不希望看到它在實際生產代碼中使用。

0

SwingWorker比使用自己的線程容易得多,因爲它爲您提供了兩件令人痛苦的事情:UI和後臺進程之間的線程協調以及循環有效,後臺工作繼續工作並將更新發送回增量式UI,如處理大量數據或加載大型列表。缺點(或優點)取決於你如何看待它,是否隱藏了底層的實現,所以未來的版本可能會有不同的行爲,性能等,這可能是不可取的。我發現它非常有用,它是UI事件和我自己的命令代碼之間的粘合劑,SwingWorker維護着與UI和我的代碼泵數據的鏈接。

1

使用Swing時,知道主要的swing處理(即渲染)發生在單個線程(這不是您的主線程)很重要。這通常稱爲Swing或awt事件線程。熟悉JDK 1.6之前版本的用戶如果花費太多時間在swing組件的事件調度器上,會記住「灰色矩形」錯誤。這是什麼意思。在任何swing應用程序中,您將有2個線程正在運行,您現在必須處理。通常,如果事件調度程序中的所有操作(被觸發的代碼表示單擊按鈕的時間)很短(即更改一個siwng按鈕的狀態),則可以在事件調度程序中運行該操作。如果您的應用程序要調用Web服務或數據庫,或者您的應用程序狀態是由外部事件(即.jms)驅動的,或者您想讓您的UI更具交互性(即構建項目列表並能夠做別的事情)你應該使用awt事件線程以外的線程(主要的一個線程)。因此,在這些情況下,您會生成一個新線程並執行必要的操作,並且當結果最終返回時,您必須創建一個可以由awt/swing調度程序執行的事件。 SwingWorker是一個很好的小設計模式,可以讓你做到這一點(另一種方式是SwingUtilities)。這對於從外部源獲取數據或者說長時間計算(渲染圖形場景)特別有用。它有助於自動化分派以及隨後從外部線程(awt線程除外)重新集成結果。對於異步事件(即來自JMS的事件需要更新結果,請使用SwingUtilities)。

相關問題