2009-10-22 68 views
0

很確定所有這些方法都能正常工作,但我會很欣賞哪種方法是最好的。使用invokeLater

考慮到參數的緣故,你有UI更改代碼和合理密集(平均500毫秒)邏輯代碼混合的(不幸的)場景,並且不可分離。所有不斷變化的UI組件都在一個面板上。

01 new Thread(){ 
02 public void run(){ 
03 
04 for (int i = 0; i < 100; i++){ 
05  // some processing 
06  doSomething(); 
07  // update some ui components 
08  panel.doSomeUi(); 
09 } 
10 
11 panel.revalidate(); 
12 panel.repaint(); 
13 
14 }}.start(); 

您會選擇以下3種方法中的哪一種,爲什麼?

  1. 包裹在invokeLater的所有代碼
  2. 內doSomeUi(
  3. 調用invokeLater的),然後再次重新驗證/重繪
  4. 只使用了invokeLater進行重新驗證/在結束

重繪對於礦:

選項1將掛起事件處理線程(EPT),同時發生所有處理

選項2在開銷時會考慮許多新的可運行參數,並且在特殊情況下可能會導致ui在半完成狀態下更新,如果組件需要某些後續ui更改纔會生效

選項3將是最高效但可能有一些線程安全問題

熱衷於聽取其他意見。

回答

3

的doSomeUi()一定要包裹 一個在invokeLater()應該觸發任何重繪/重繪是必要的 - Swing UI線程將在您繼續計算時進行繪製。

在現代虛擬機上創建大量短暫的Runnable的開銷很小,不應該成爲問題。

所以,選項2(與建議的修改)應該是它。在編寫多線程代碼時,慢速和正確總是比快速和隨機錯誤更好。

+0

我會接受這個答案,除非有人進一步深入... – pstanton 2009-10-23 01:47:13

-2

您是否閱讀Java Lesson: Concurrency in Swing並考慮使用工作線程。同時檢查TumbleItem Example

的課程明確表示:在事件調度線程 必須迅速完成

任務;如果他們不這樣做,則 未處理的事件備份和用戶 接口變爲無響應。

當一個Swing程序需要執行 一個長時間運行的任務,它通常使用的工作線程

+0

謝謝,但這並沒有多大改變,本質上你說你會使用一個工具類或許多工具類的實例來做同樣的事情......我沒有使用SwingWorker,因爲它是相對較新的,但我的理解是,它只是一個便利類來封裝兩部分任務 - 處理+ UI。對? – pstanton 2009-10-23 00:47:14

1

我首先會讓它運行單線程。作爲這個組成部分,我會確保我有很好的代碼(例如不擴展ThreadJPanel),「業務」邏輯和UI,測試等有很好的分離。它可能不是令人印象深刻的,但它是可交付的。檢查到版本控制。然後或許看看是否有一個我可以同時做的小部分。

存在解決多線程問題的極端方法。在沒有共享狀態的情況下,我們可以將不可變動作事件從UI中排出,並將不可變更新事件排入隊列以替換模型的UI副本。或者,我們可以共享狀態並且非常小心地鎖定(我建議最大的鎖可能可以工作 - 小心回調)。

注意到您不必爲每一件小事添加監聽器可能很有用。您可以使用粗粒度偵聽器,然後快速掃描數據結構以進行更新。

需要注意的重要一點是,UI發送到「業務」模型的操作和狀態反向更新應該儘可能分離(即從SwingWorker運行)。

+0

首先,我什麼時候提及擴展JPanel?其次,雖然你的建議聽起來不錯,但我不明白它與問題的關係。我清楚地表明,出於理由,好的分離是不可能的。也許這是一個有缺陷的問題,但我試圖解決的問題更多的是在整個過程中鎖定EDT,在整個過程中多次鎖定EDT,或者執行大部分關閉EDT的UI任務和然後通過在最後的EDT上重新繪製/驗證來「重新同步」。 – pstanton 2009-10-23 01:45:11

+1

'panel.doSomeUi();'*建議*擴展'JPanel'給我。也許'doSomeUi'是一些「JPanel」方法的代表,但是EDT的選擇有限。如果分離是「不可能的」,正如我在第一段中所建議的那樣,第一步就是做「不可能的事」。 – 2009-10-23 02:11:21

+0

好的,我應該寫doSomeUi(面板);它意味着是一個半sudo代碼,例如,它會在單個容器的範圍內提示ui代碼。 – pstanton 2009-10-23 05:34:24

1

重新驗證並重繪是線程安全的。他們有自己的invokeLater內置的東西,你可以隨時調用任何線程的重新驗證和重繪。它甚至是如此聰明,以至於如果您在實際驗證任何內容之前調用了一千次重新驗證,它會將所有這些千次呼叫放到一個呼叫中。