2012-07-30 39 views
1

我正在構建一個Java應用程序,並且實現了自定義偵聽器和事件。現在的問題是有很多事件和監聽器,而應用程序GUI線程在監聽器處理事件時被阻塞。這可以使用事件調度線程來解決嗎?如果是這樣如何?事件派發線程上的java自定義事件

聽衆代碼:

public class ProjectChangeObserver 
{ 
    private List<ProjectChangeListener> listeners = new ArrayList<ProjectChangeListener>(); 

    public void addProjectChangeListener(ProjectChangeListener l) 
    { 
     listeners.add(l); 
    } 

    public void removeProjectChangeListener(ProjectChangeListener l) 
    { 
     listeners.remove(l); 
    } 

    public void removeAllProjectChangeListeners() 
    { 
     listeners.clear(); 
    } 

    public void fireProjectChange(ProjectChangeEvent e) 
    { 
     if(listeners.size() > 0) 
     { 
      ArrayList<ProjectChangeListener> safeCopy = new ArrayList<ProjectChangeListener>(listeners); 
      for (ProjectChangeListener cl : safeCopy) { 
       cl.onProjectChange(e); 
     } 
     } 
    } 
} 

回答

3

Swing的一個特點是它是single-threaded

但是,沒有什麼能阻止你產生自己的線程來做後臺處理。只要您只撥打revalidate()repaint(),則所有繪圖仍將在Swing線程中處理。 (請記住,如果您打算派生其他線程來執行後臺工作,那麼確保您的變量被聲明爲volatile,前提是您希望Swing線程看到與您的線程中相同的值;或者將信息傳回另一位聽衆)。

如果您打算在單獨的線程中自行繪製繪畫(例如自定義組件),則根據具體情況要麼不可能要麼強烈不鼓勵。 (一些奇特的情況可能允許在自定義線程安全緩衝類中多CPU生成一個場景,但你不太可能這樣做)。

如果你發現你的Listener是CPU /網絡密集型的,那麼你可能想要考慮誰在做大部分喊叫和誰在聽的架構。我總是儘量減少在我的「查看」代碼中大喊大叫,以便它只是響應事件。

順便說一句,我發現Project Lombok和貝塔姐姐Lombok PG大大減少@ListenerSupport實施Listener模式的樣板。

+0

更精確的實現一個粘貼操作,它只是將一些元素複製到一個矢量(響應事件),但問題是如果有很多元素會阻塞GUI線程。所以,如果我明白你的答案,我應該產生一個新的線程,並在那裏做粘貼操作? – blejzz 2012-07-30 11:15:36

+0

嗯,這是一個棘手的問題,因爲用戶正在生成一個事件,並且您的視圖正在響應它。如果您在單獨的線程中實施處理,然後觸發輕量級事件(視圖可以快速處理),那麼您的用戶將被迫遇到短暫的延遲。由於我對你的項目的理解有限,我實際上建議你看看加快視圖的處理代碼,而不會陷入線程的困擾。 – fommil 2012-07-30 11:59:28

1

恰恰相反,這必須解決避免事件分派線程(「GUI線程」是同一件事的另一個名稱)。您必須使用SwingWorker在其自己的線程中啓動異步任務。

+0

因此,如果我理解正確的EDT應該只用於GUI,如果我想要自定義事件我需要在新線程中觸發事件(並避免EDT)? – blejzz 2012-07-30 10:50:28

+0

只要您的偵聽器方法的任何一次調用都不需要太多時間,您就可以在EDT中執行任何您喜歡的代碼。 GUI在處理程序運行時凍結。 – 2012-07-30 11:43:59

1

如果您想阻止UI阻塞,則應爲您的事件運行單獨的線程。

如果您想爲事件使用單個線程,那麼您可以創建線程,並且可以使用存儲事件的隊列將命令傳遞到事件線程。

但是,如果可能的話,您應該爲您的事件打開異步線程,並且您應該確保在需要時刷新UI。